My code is throwing an empty list error. When I run:
makeAgent :: Agent -> [Agent] -> Agent
makeAgent (Agent func n _) agents = (Agent func (n++(show $ length $ sameNames n agents)) empty) --appends number to name to differentiate agents
where sameNames n agents = filter (findName n) agents
findName n1 (Agent _ n2 _) = (slice 0 3 n1) == (slice 0 3 n2) --ignore the suffix
empty = head $ getEmpty (positions agents) (fst $ getGrid agents) --getGrid returns a tuple, but currently assume to be a square
baseline :: [Interaction] -> Float
baseline int = (fromIntegral total)/len
where total = sum sums
sums = map snd (showSums int)
agents = nub $ map (\(Interaction a1 a2 _ ) -> a2) int
len = fromIntegral $ length agents
reproduce :: Float -> [Interaction] -> [Agent] --so baseline isn't recalulated every time
reproduce _ [] = []
reproduce base interaction = winners ++ [newAgent] ++ reproduce base (tail interaction)
where agents = nub $ concat $ map (\(Interaction a1 a2 _ ) -> a1:a2:[]) interaction
winners = [a | a <- agents, (sumAgent interaction a) >= (round base)]
newAgent = makeAgent (head winners) winners
main = do
output "Length" (fromIntegral $ length int)
output "Baseline" base
output "Agents" agents
output "Sums" (showSums int)
output "winners" winners
output "NeAgent" (makeAgent (head winners)winners)
output "New Agents" (reproduce base int)
where agents = generate 4
int = playRound agents 20
base = baseline int
winners = [a | a <- agents, (sumAgent int a) >= (round base)]
What this reproduce, the main function, should be doing is generating a new agent based on whether their parents "fitness" is over a certain level, then run the same function with all but that agent in the list of agents.
It outputs:
Length: 16
Baseline: 280.0
Agents: [c_pavlov(-1,-1),c_titForTat(-1,0),c_sucker(-1,1),b_grim(0,-1)]
Sums: [("c_pavlov",280),("c_titForTat",280),("c_sucker",280),("b_grim",280)]
winners: [c_pavlov(-1,-1),c_titForTat(-1,0),c_sucker(-1,1),b_grim(0,-1)]
NeAgent: c_pavlov1(0,0)
prisoners: Prelude.head: empty list
When I call reproduce, it throws the prelude.head empty list error, and the winners,agent, and int lists are all non-empty, so it may be an edge case error on the last iteration of the recursion. Why is this happening?
The solution is relatively simple: Simply do not use head and tail in Haskell programs. (While there are a few situation where it is reasonable to do so, it's best to assume in the beginning that there aren't.)
Instead, use pattern matching. Usually, you will always want to properly pattern match on both the empty list and the non-empty list, like this:
fun :: [Something] -> ...
fun [] = ...
fun (x : xs) = ... -- x is head, xs is tail
This way, you are forced to deal with the error, and you know that referring to x and xs cannot fail anymore, because the list has already been determined to be non-empty.
If you have lots of lists in your program that should never be empty, then you have to manually keep track of these conditions (and should at least document them). But even then, it's better to pattern match in a let-binding like this
(winner : _) = ...
and then refer to winner as the head of that list later, because you will get an error message involving the line number where the pattern match failed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With