
Hi, / Disclaimer: I have been learning Haskell for a month and there are still several things about this wonderful language I know nothing of, so please bear with me. Also, I apologize for this (somewhat) long mail./ I came across this article: http://unriskinsight.blogspot.co.at/2014/06/fast-functional-goats-lions-and-... a couple of days ago. This compares performance of solving a problem (which I will get to) using the functional constructs alone in languages like C++11 and Java 8. Since, Haskell is my first foray into FP, I thought I should try solving this in Haskell. So the problem at hand is this: There is a magical forest which has only Lions, Wolves and Goats. Lions are stronger than Wolves which are in turn stronger than Goats. Each strong animal is capable of eating a weaker animal, which also in turn transforms the '/eater/' into an animal which was not involved. /i.e./ If a Lion eats a Wolf it gets transformed into a Goat. If a Wolf eats a Sheep it gets transformed into a Lion. Below are the two versions of the code I came up with to solve this. Neither of them converge to the 'endStates' even after about 15 minutes. So there is definitely something wrong with what I have done. But after banging my head on the keyboard for more then a day with this, I would appreciate some pointers or help. -- version 1 import Data.List data Animal = Lion Int | Wolf Int | Goat Int deriving (Show, Eq) type Forest = [Animal] -- lions f = count 0 f -- where -- count acc [] = acc -- count acc ((Lion a):as) = acc + a + (count acc as) -- count acc (_:as) = acc + (count acc as) -- wolfs f = count 0 f -- where -- count acc [] = acc -- count acc ((Wolf a):as) = acc + a + (count acc as) -- count acc (_:as) = acc + (count acc as) -- goats f = count 0 f -- where -- count acc [] = acc -- count acc ((Goat a):as) = acc + a + (count acc as) -- count acc (_:as) = acc + (count acc as) lions [Lion l, Wolf w, Goat g] = l wolfs [Lion l, Wolf w, Goat g] = w goats [Lion l, Wolf w, Goat g] = g --Invalid eat calls are returned with [], to denote termination eat :: Forest -> Animal -> Animal -> Forest eat f (Lion _) (Goat le) = if (l >= le && g >= le) then [Lion (l-le), Wolf (w+le), Goat (g-le)] else [] where l = lions f w = wolfs f g = goats f eat f (Lion _) (Wolf le) = if (l >= le && w >= le) then [Lion (l-le), Wolf (w-le), Goat (g+le)] else [] where l = lions f w = wolfs f g = goats f eat f (Wolf _) (Goat we) = if (w >= we && g >= we) then [Lion (l+we), Wolf (w-we), Goat (g-we)] else [] where l = lions f w = wolfs f g = goats f eat _ _ _ = [] lionEatGoat :: Forest -> Forest lionEatGoat f = eat f (Lion 0) (Goat 1) lionEatWolf :: Forest -> Forest lionEatWolf f = eat f (Lion 0) (Wolf 1) wolfEatGoat :: Forest -> Forest wolfEatGoat f = eat f (Wolf 0) (Goat 1) meal :: Forest -> [Forest] meal [] = [] meal f@[Lion l, Wolf w, Goat g] | endState f = [] | l == 0 = [f] ++ weg | w == 0 = [f] ++ leg | g == 0 = [f] ++ lew | (l /= 0) && (w /= 0) && (g /= 0) = [f] ++ leg ++ lew ++ weg | otherwise = [] where leg = meal $ lionEatGoat f lew = meal $ lionEatWolf f weg = meal $ wolfEatGoat f endState :: Forest -> Bool endState f = if ((l == 0 && g == 0) || (l == 0 && w == 0) || (w == 0 && g == 0)) then True else False where l = lions f w = wolfs f g = goats f endStates = filter endState main = do putStrLn $ show $ endStates $ meal [Lion 6, Wolf 55, Goat 17] I thought using the ADT was causing the performance issue and reverted to using a plain 3-termed list which holds [Lion count, Wolf Count, Sheep Count] :: [Int] -- version 2 import Data.List lionEatGoat :: [Int] -> [Int] lionEatGoat [l,w,g] = [l-1,w+1,g-1] lionEatWolf :: [Int] -> [Int] lionEatWolf [l,w,g] = [l-1,w-1,g+1] wolfEatGoat :: [Int] -> [Int] wolfEatGoat [l,w,g] = [l+1,w-1,g-1] meal :: [Int] -> [[Int]] meal [] = [] meal f@[l, w, g] | endState f = [] | l == 0 = (f:weg:(meal weg)) | w == 0 = (f:leg:(meal leg)) | g == 0 = (f:lew:(meal lew)) | (l /= 0) && (w /= 0) && (g /= 0) = (f:leg:lew:weg:(meal leg ++ meal lew ++ meal weg)) | otherwise = [] where leg = lionEatGoat f lew = lionEatWolf f weg = wolfEatGoat f endState :: [Int] -> Bool endState [l,w,g] = if ((l == 0 && g == 0) || (l == 0 && w == 0) || (w == 0 && g == 0)) then True else False endStates = filter endState main = do putStrLn $ show $ endStates $ meal [Lion 6, Wolf 55, Goat 17] This is still extremely slow, without the program ever terminating. Can someone please tell me what I am doing wrong. -Elric