I am learning Haskell.
I am trying to find elements of a list as which sum to elements of a list bs, returning the elements as a tuple:
findSum2 :: [Int] -> [Int] -> [(Int,Int,Int)] findSum2 as bs = [(a, a', b) | a <- as, a' <- as, b <- bs, a + a' == b] The code works. But in order to learn Haskell, I'm trying to rewrite it as do-notation:
findSum2 :: [Int] -> [Int] -> [(Int,Int,Int)] findSum2 as bs = do a <- as a' <- as b <- bs if a + a' == b then return (a, a', b) else return () The type-checker then complains at me:
• Couldn't match type ‘()’ with ‘(Int, Int, Int)’ Expected type: [(Int, Int, Int)] Actual type: [()] In all fairness, I knew it would. But since I can't skip the else clause in Haskell, what should I put in the return statement in the else clause?
Thanks.
return (a,a',b)means the singleton list[(a,a',b)]which signals "I found a triple,(a,a',b), add it to the result list". Similarly,return ()means[()], i.e. "I found a triple,(), add it to the result list", triggering a type error since that's no triple. To signal, "I found no triple this time" use the empty list[](without anyreturn).return [], but clearly that was wrong too. I think I'm still struggling withdo-notation. How did you get to a place where you could recognize when to return automatically?[]), so you need to keep in mind what's just a random value and what's a monadic action.returnis not a magic primitive, but a function that turns any valuexinto a boring monadic action that only has that value inside (the singleton list[x], in this monad). If you havex = [], do you really need to wrap it inside a list again?[ a | a <- [1,2,3] ]and[ a | a <- [[1,2,3]] ]. In the former,aranges over1,2,3, while in the latterahas only one value, the list[1,2,3]. That's because we added an extra[.....]. We probably didn't want that, and that's the same issue that you found between[]andreturn [](i.e.,[[]]). In the list monad, usereturnonly what you want to signal "one value found", not "no values found here".returninside ado-block, do you automatically also stare at the type signature to understand whichreturnis being called? (That's what I'm starting to do now.)