Haskell Pattern Matching (beginner) - haskell

I have to implement a small programm in Haskell that increments/decrements a result by what in the console line is. For example if we have -a in the console the results must be 0, if -b the result must be incremented with 6 and so on. I have to do this with pattern matching.
I haven't used Haskell until now and I find it pretty hard to understand. I have this to start with:
import System.Environment
main = getArgs >>= print . (foldr apply 0) . reverse
apply :: String -> Integer -> Integer
I don't understand what in the main is. What does it make and the reverse from end, what does it do? As I've read on the internet the getArgs function gives me the values from the console line. But how can I use them? Are there are equivalent functions like for/while in Haskell?
Also, if you have some examples or maybe could help me, I will be very thankful.
Thanks!

This is not beginner-friendly code. Several shortcuts are taken there to keep the code very compact (and in pointfree form). The code
main = getArgs >>= print . (foldr apply 0) . reverse
can be expanded as follows
main = do
args <- getArgs
let reversedArgs = reverse args
result = foldr apply 0 reversedArgs
print result
The result of this can be seen as follows. If the command line arguments are, say, args = ["A","B","C"], then we get reversedArgs = ["C","B","A"] and finally
result = apply "C" (apply "B" (apply "A" 0))
since foldr applies the function apply in such way.
Honestly, I'm unsure about why the code uses reverse and foldr for your task. I would have considered foldl (or, to improve performance, foldl') instead.

I expect the exercise is not to touch the given code, but to expand on it to perform your function. It defines a complicated-looking main function and declares the type of a more straight forward apply, which is called but not defined.
import System.Environment -- contains the function getArgs
-- main gets arguments, does something to them using apply, and prints
main = getArgs >>= print . (foldr apply 0) . reverse
-- apply must have this type, but what it does must be elsewhere
apply :: String -> Integer -> Integer
If we concentrate on apply, we see that it receives a string and an integer, and returns an integer. This is the function we have to write, and it can't decide control flow, so we can just get to it while hoping the argument handling works out.
If we do want to figure out what main is up to, we can make a few observations. The only integer in main is 0, so the first call must get that as its second argument; later ones will be chained with whatever is returned, as that's how foldr operates. r stands for from the right, but the arguments are reversed, so this still processes arguments from the left.
So I could go ahead and just write a few apply bindings to make the program compile:
apply "succ" n = succ n
apply "double" n = n + n
apply "div3" n = n `div` 3
This added a few usable operations. It doesn't handle all possible strings.
$ runhaskell pmb.hs succ succ double double succ div3
3
$ runhaskell pmb.hs hello?
pmb.hs: pmb.hs:(5,1)-(7,26): Non-exhaustive patterns in function apply
The exercise should be about how you handle the choice of operation based on the string argument. There are several options, including distinct patterns as above, pattern guards, case and if expressions.
It can be useful to examine the used functions to see how they might fit together. Here's a look at a few of the used functions in ghci:
Prelude> import System.Environment
Prelude System.Environment> :t getArgs
getArgs :: IO [String]
Prelude System.Environment> :t (>>=)
(>>=) :: Monad m => m a -> (a -> m b) -> m b
Prelude System.Environment> :t print
print :: Show a => a -> IO ()
Prelude System.Environment> :t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c
Prelude System.Environment> :t foldr
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
Prelude System.Environment> :t reverse
reverse :: [a] -> [a]
This shows that all the strings come out of getArgs, it and print operate in the IO monad, which must be the m in >>=, and . transfers results from the right function into arguments for the left function. The type signature alone doesn't tell us what order foldr handles things, though, or what reverse does (though it can't create new values, only reorder including repetition).
As a last exercise, I'll rewrite the main function in a form that doesn't switch directions as many times:
main = print . foldl (flip apply) 0 =<< getArgs
This reads from right to left in a data flow sense and handles arguments from left to right because foldl performs left-associative folding. flip is just there to match the argument order for apply.

As suggested in the comment, hoogle is a great tool.
To find out what exactly you get from getArgs you can search for it on hoogle:
https://hackage.haskell.org/package/base-4.11.1.0/docs/System-Environment.html#v:getArgs
As you can see, it's of type IO [String].
Since I don't know how familiar you are with the IO abstractions yet, we'll just say that the right part of >>= gets those as argument.
The arguments for a call like ./a.out -a -b --asdf Hi will then be a list of strings:
["-a", "-b", "--asdf", "Hi"].
The fold + reverse in the main will then do some magic, and your apply function will be called with each string in the list and the previous return value (0 for the first invocation).
In Haskell, String is the same as [Char] with a bit of compiler sugar, so you can match on strings like you would on regular lists in your definition of apply.

Related

When to use foldr with a continuation as an accumulation function?

There is a technique I've seen a few times with foldr. It involves using a function in place of the accumulator in a foldr. I'm wondering when it is necessary to do this, as opposed to using an accumulator that is just a regular value.
Most people have seen this technique before when using foldr to define foldl:
myFoldl :: forall a b. (b -> a -> b) -> b -> [a] -> b
myFoldl accum nil as = foldr f id as nil
where
f :: a -> (b -> b) -> b -> b
f a continuation b = continuation $ accum b a
Here, the type of the combining function f is not just a -> b -> b like normal, but a -> (b -> b) -> b -> b. It takes not only an a and b, but a continuation (b -> b) that we need to pass the b to in order to get the final b.
I most recently saw an example of using this trick in the book Parallel and Concurrent Programming in Haskell. Here is a link to the source code of the example using this trick. Here is a link to the chapter of the book explaining this example.
I've taken the liberty of simplifying the source code into a similar (but shorter) example. Below is a function that takes a list of Strings, prints out whether each string's length is greater than five, then prints the full list of only the Strings that have a length greater than five:
import Text.Printf
stringsOver5 :: [String] -> IO ()
stringsOver5 strings = foldr f (print . reverse) strings []
where
f :: String -> ([String] -> IO ()) -> [String] -> IO ()
f str continuation strs = do
let isGreaterThan5 = length str > 5
printf "Working on \"%s\", greater than 5? %s\n" str (show isGreaterThan5)
if isGreaterThan5
then continuation $ str : strs
else continuation strs
Here's an example of using it from GHCi:
> stringsOver5 ["subdirectory", "bye", "cat", "function"]
Working on "subdirectory", greater than 5? True
Working on "bye", greater than 5? False
Working on "cat", greater than 5? False
Working on "function", greater than 5? True
["subdirectory","function"]
Just like in the myFoldl example, you can see that the combining function f is using the same trick.
However, it occurred to me that this stringsOver5 function could probably be written without this trick:
stringsOver5PlainFoldr :: [String] -> IO ()
stringsOver5PlainFoldr strings = foldr f (pure []) strings >>= print
where
f :: String -> IO [String] -> IO [String]
f str ioStrs = do
let isGreaterThan5 = length str > 5
printf "Working on \"%s\", greater than 5? %s\n" str (show isGreaterThan5)
if isGreaterThan5
then fmap (str :) ioStrs
else ioStrs
(Although maybe you could make the argument that IO [String] is a continuation?)
I have two questions regarding this:
Is it every absolutely necessary to use this trick of passing a continuation to foldr, instead of using foldr with a normal value as an accumulator? Is there an example of a function that absolutely can't be written using foldr with a normal value? (Aside from foldl and functions like that, of course.)
When would I want to use this trick in my own code? Is there any example of a function that can be significantly simplified by using this trick?
Is there any sort of performance considerations to take into account when using this trick? (Or, well, when not using this trick?)
I have two questions regarding this:
For some large value of "two" :-P
Is it every absolutely necessary to use this trick of passing a continuation to foldr? Is there an example of a function that
absolutely can't be written without this trick? (Aside from foldl and
functions like that, of course.)
No, never. Each foldr invocation can always be replaced by explicit recursion.
One should use foldr and other well-known library functions when they make the code simpler. When they do not, one should not shoehorn the code so that it fits the foldr pattern.
There is no shame in using plain recursion, when there is no obvious replacement.
Compare your code with this, for instance:
stringsOver5 :: [String] -> IO ()
stringsOver5 strings = go strings []
where
go :: [String] -> [String] -> IO ()
go [] acc = print (reverse acc)
go (s:ss) acc = do
let isGreaterThan5 = length str > 5
printf "Working on \"%s\", greater than 5? %s\n" str (show isGreaterThan5)
if isGreaterThan5
then go ss (s:acc)
else go ss acc
When would I want to use this trick in my own code? Is there any example of a function that can be significantly simplified by using
this trick?
In my humble opinion, almost never.
Personally, I find "calling foldr with four (or more) arguments" to be an anti-pattern in most cases. This is because it is not that shorter than using explicit recursion, and has the potential to be much less readable.
I would argue that this "idiom" is quite puzzling to any Haskeller who has not seen it before. It is a sort-of an acquired taste, so to speak.
Perhaps, it could be a good idea to use this style when the continuation functions are meaningful on their own. E.g., when representing lists as difference lists, the concatenation of a regular-list of difference-lists can be quite elegant
foldr (.) id listOfDLists []
is beautiful, even if the last [] might be puzzling at first.
Is there any sort of performance considerations to take into account when using this trick? (Or, well, when not using this trick?)
Performance should be essentially the same as using explicit recursion. GHC could even generate the exact same code.
Perhaps using foldr could help GHC fire some fold/build optimization rules, but I'm unsure about the need to do that when using continuations.

Haskell's (<-) in Terms of the Natural Transformations of Monad

So I'm playing around with the hasbolt module in GHCi and I had a curiosity about some desugaring. I've been connecting to a Neo4j database by creating a pipe as follows
ghci> pipe <- connect $ def {credentials}
and that works just fine. However, I'm wondering what the type of the (<-) operator is (GHCi won't tell me). Most desugaring explanations describe that
do x <- a
return x
desugars to
a >>= (\x -> return x)
but what about just the line x <- a?
It doesn't help me to add in the return because I want pipe :: Pipe not pipe :: Control.Monad.IO.Class.MonadIO m => m Pipe, but (>>=) :: Monad m => m a -> (a -> m b) -> m b so trying to desugar using bind and return/pure doesn't work without it.
Ideally it seems like it'd be best to just make a Comonad instance to enable using extract :: Monad m => m a -> a as pipe = extract $ connect $ def {creds} but it bugs me that I don't understand (<-).
Another oddity is that, treating (<-) as haskell function, it's first argument is an out-of-scope variable, but that wouldn't mean that
(<-) :: a -> m b -> b
because not just anything can be used as a free variable. For instance, you couldn't bind the pipe to a Num type or a Bool. The variable has to be a "String"ish thing, except it never is actually a String; and you definitely can't try actually binding to a String. So it seems as if it isn't a haskell function in the usual sense (unless there is a class of functions that take values from the free variable namespace... unlikely). So what is (<-) exactly? Can it be replaced entirely by using extract? Is that the best way to desugar/circumvent it?
I'm wondering what the type of the (<-) operator is ...
<- doesn't have a type, it's part of the syntax of do notation, which as you know is converted to sequences of >>= and return during a process called desugaring.
but what about just the line x <- a ...?
That's a syntax error in normal haskell code and the compiler would complain. The reason the line:
ghci> pipe <- connect $ def {credentials}
works in ghci is that the repl is a sort of do block; you can think of each entry as a line in your main function (it's a bit more hairy than that, but that's a good approximation). That's why you need (until recently) to say let foo = bar in ghci to declare a binding as well.
Ideally it seems like it'd be best to just make a Comonad instance to enable using extract :: Monad m => m a -> a as pipe = extract $ connect $ def {creds} but it bugs me that I don't understand (<-).
Comonad has nothing to do with Monads. In fact, most Monads don't have any valid Comonad instance. Consider the [] Monad:
instance Monad [a] where
return x = [x]
xs >>= f = concat (map f xs)
If we try to write a Comonad instance, we can't define extract :: m a -> a
instance Comonad [a] where
extract (x:_) = x
extract [] = ???
This tells us something interesting about Monads, namely that we can't write a general function with the type Monad m => m a -> a. In other words, we can't "extract" a value from a Monad without additional knowledge about it.
So how does the do-notation syntax do {x <- [1,2,3]; return [x,x]} work?
Since <- is actually just syntax sugar, just like how [1,2,3] actually means 1 : 2 : 3 : [], the above expression actually means [1,2,3] >>= (\x -> return [x,x]), which in turn evaluates to concat (map (\x -> [[x,x]]) [1,2,3])), which comes out to [1,1,2,2,3,3].
Notice how the arrow transformed into a >>= and a lambda. This uses only built-in (in the typeclass) Monad functions, so it works for any Monad in general.
We can pretend to extract a value by using (>>=) :: Monad m => m a -> (a -> m b) -> m b and working with the "extracted" a inside the function we provide, like in the lambda in the list example above. However, it is impossible to actually get a value out of a Monad in a generic way, which is why the return type of >>= is m b (in the Monad)
So what is (<-) exactly? Can it be replaced entirely by using extract? Is that the best way to desugar/circumvent it?
Note that the do-block <- and extract mean very different things even for types that have both Monad and Comonad instances. For instance, consider non-empty lists. They have instances of both Monad (which is very much like the usual one for lists) and Comonad (with extend/=>> applying a function to all suffixes of the list). If we write a do-block such as...
import qualified Data.List.NonEmpty as N
import Data.List.NonEmpty (NonEmpty(..))
import Data.Function ((&))
alternating :: NonEmpty Integer
alternating = do
x <- N.fromList [1..6]
-x :| [x]
... the x in x <- N.fromList [1..6] stands for the elements of the non-empty list; however, this x must be used to build a new list (or, more generally, to set up a new monadic computation). That, as others have explained, reflects how do-notation is desugared. It becomes easier to see if we make the desugared code look like the original one:
alternating :: NonEmpty Integer
alternating =
N.fromList [1..6] >>= \x ->
-x :| [x]
GHCi> alternating
-1 :| [1,-2,2,-3,3,-4,4,-5,5,-6,6]
The lines below x <- N.fromList [1..6] in the do-block amount to the body of a lambda. x <- in isolation is therefore akin to a lambda without body, which is not a meaningful thing.
Another important thing to note is that x in the do-block above does not correspond to any one single Integer, but rather to all Integers in the list. That already gives away that <- does not correspond to an extraction function. (With other monads, the x might even correspond to no values at all, as in x <- Nothing or x <- []. See also Lazersmoke's answer.)
On the other hand, extract does extract a single value, with no ifs or buts...
GHCi> extract (N.fromList [1..6])
1
... however, it is really a single value: the tail of the list is discarded. If we want to use the suffixes of the list, we need extend/(=>>)...
GHCi> N.fromList [1..6] =>> product =>> sum
1956 :| [1236,516,156,36,6]
If we had a co-do-notation for comonads (cf. this package and the links therein), the example above might get rewritten as something in the vein of:
-- codo introduces a function: x & f = f x
N.fromList [1..6] & codo xs -> do
ys <- product xs
sum ys
The statements would correspond to plain values; the bound variables (xs and ys), to comonadic values (in this case, to list suffixes). That is exactly the opposite of what we have with monadic do-blocks. All in all, as far as your question is concerned, switching to comonads just swaps which things we can't refer to outside of the context of a computation.

Define a haskell function [IO a] -> IO[a]

I am doing a haskell exercise, regarding define a function accumulate :: [IO a] -> IO [a]
which performs a sequence of interactions and accumulates their result in a list.
What makes me confused is how to express a list of IO a ? (action:actions)??
how to write recursive codes using IO??
This is my code, but these exists some problem...
accumulate :: [IO a] -> IO [a]
accumulate (action:actions) = do
value <- action
list <- accumulate (action:actions)
return (convert_to_list value list)
convert_to_list:: Num a =>a -> [a]-> [a]
convert_to_list a [] = a:[]
convert_to_list x xs = x:xs
What you are trying to implement is sequence from Control.Monad.
Just to let you find the answer instead of giving it, try searching for [IO a] -> IO [a] on hoogle (there's a Source link on the right hand side of the page when you've chosen a function).
Try to see in your code what happens when list of actions is empty list and see what does sequence do to take care of that.
There is already such function in Control.Monad and it called sequence (no you shouldn't look at it). You should denote the important decision taken during naming of it. Technically [IO a] says nothing about in which order those Monads should be attached to each other, but name sequence puts a meaning of sequential attaching.
As for the solving you problem. I'd suggest to look more at types and took advice of #sacundim. In GHCi (interpreter from Glasgow Haskell Compiler) there is pretty nice way to check type and thus understand expression (:t (:) will return (:) :: a -> [a] -> [a] which should remind you one of you own function but with less restrictive types).
First of all I'd try to see at what you have showed with more simple example.
data MyWrap a = MyWrap a
accumulate :: [MyWrap a] -> MyWrap [a]
accumulate (action:actions) = MyWrap (convert_to_list value values) where
MyWrap value = action -- use the pattern matching to unwrap value from action
-- other variant is:
-- value = case action of
-- MyWrap x -> x
MyWrap values = accumulate (action:actions)
I've made the same mistake that you did on purpose but with small difference (values is a hint). As you probably already have been told you could try to interpret any of you program by trying to inline appropriate functions definitions. I.e. match definitions on the left side of equality sign (=) and replace it with its right side. In your case you have infinite cycle. Try to solve it on this sample or your and I think you'll understand (btw your problem might be just a typo).
Update: Don't be scary when your program will fall in runtime with message about pattern match. Just think of case when you call your function as accumulate []
Possibly you looking for sequence function that maps [m a] -> m [a]?
So the short version of the answer to your question is, there's (almost) nothing wrong with your code.
First of all, it typechecks:
Prelude> let accumulate (action:actions) = do { value <- action ;
list <- accumulate (action:actions) ; return (value:list) }
Prelude> :t accumulate
accumulate :: (Monad m) => [m t] -> m [t]
Why did I use return (value:list) there? Look at your second function, it's just (:). Calling g
g a [] = a:[]
g a xs = a:xs
is the same as calling (:) with the same arguments. This is what's known as "eta reduction": (\x-> g x) === g (read === as "is equivalent").
So now just one problem remains with your code. You've already taken a value value <- action out of the action, so why do you reuse that action in list <- accumulate (action:actions)? Do you really have to? Right now you have, e.g.,
accumulate [a,b,c] ===
do { v1<-a; ls<-accumulate [a,b,c]; return (v1:ls) } ===
do { v1<-a; v2<-a; ls<-accumulate [a,b,c]; return (v1:v2:ls) } ===
do { v1<-a; v2<-a; v3<-a; ls<-accumulate [a,b,c]; return (v1:v2:v3:ls) } ===
.....
One simple fix and you're there.

Haskell beginner, trying to output a list

I suppose everyone here already has seen one of these (or at least a similar) question, still I need to ask because I couldn't find the answer to this question anywhere (mostly because I don't know what exactly I should be looking for)
I wrote this tiny script, in which printTriangle is supposed to print out the pascal triangle.
fac = product . enumFromTo 2
binomial n k = (product (drop (k-1) [2..n])) `div` (fac (n-k))
pascalTriangle maxRow =
do row<-[0..maxRow-1]
return (binomialRow row)
where
binomialRow row =
do k<-[0..row]
return (binomial row k)
printTriangle :: Int -> IO ()
printTriangle rows = do row<-(triangle)
putStrLn (show row)
where
triangle = pascalTriangle rows
Now for reasons that are probably obvious to the trained eye, but completely shrouded in mystery for me, i get the following error when trying to load this in ghci:
Couldn't match expected type `IO t0' with actual type `[[Int]]'
In a stmt of a 'do' expression: row <- (triangle)
In the expression:
do { row <- (triangle);
putStrLn (show row) }
In
an equation for `printTriangle':
printTriangle rows
= do { row <- (triangle);
putStrLn (show row) }
where
triangle = pascalTriangle rows
what im trying to do is something like I call printTriangle like this:
printTriangle 3
and I get this output:
[1]
[1,1]
[1,2,1]
If anyone could explain to me why what I'm doing here doesn't work (to be honest, I am not TOO sure what exactly I am doing here; I am used to imperative languages and this whole functional programming thingy is still mighty confusing to me), and how I could do it in a less dumb fashion that would be great.
Thanks in advance.
You said in a comment that you thought lists were monads, but now you're not sure -- well, you're right, lists are monads! So then why doesn't your code work?
Well, because IO is also a monad. So when the compiler sees printTriangle :: Int -> IO (), and then do-notation, it says "Aha! I know what to do! He's using the IO monad!" Try to imagine its shock and dispair when it discovers that instead of IO monads, it finds list monads inside!
So that's the problem: to print, and deal with the outside world, you need to use the IO monad; inside the function, you're trying to use lists as the monad.
Let's see how this is a problem. do-notation is Haskell's syntactic sugar to lure us into its cake house and eat us .... I mean it's syntactic sugar for >>= (pronounced bind) to lure us into using monads (and enjoying it). So let's write printTriangle using bind:
printTriangle rows = (pascalTriangle rows) >>= (\row ->
putStrLn $ show row)
Okay, that was straightforward. Now do we see any problems? Well, lets look at the types. What's the type of bind? Hoogle says: (>>=) :: Monad m => m a -> (a -> m b) -> m b. Okay, thanks Hoogle. So basically, bind wants a monad type wrapping a type a personality, a function that turns a type a personality into (the same) monad type wrapping a type-b personality, and ends up with (the same) monad type wrapping a type-b personality.
So in our printTriangle, what do we have?
pascalTriangle rows :: [[Int]] -- so our monad is [], and the personality is [Int]
(\row -> putStrLn $ show row) :: [Int] -> IO () -- here the monad is IO, and the personality is ()
Well, crap. Hoogle was very clear when it told us that we had to match our monad types, and instead, we've given >>= a list monad, and a function that produces an IO monad. This makes Haskell behave like a little kid: it closes its eyes and stomps on the floor screaming "No! No! No!" and won't even look at your program, much less compile it.
So how do we appease Haskell? Well, others have already mentioned mapM_. And adding explicit type signatures to top-level functions is also a good idea -- it can sometimes help you to get compile errors sooner, rather than later (and get them you will; this is Haskell after all :) ), which makes it much much easier to understand the error messages.
I'd suggest writing a function that turns your [[Int]] into a string, and then printing the string out separately. By separating the conversion into a string from the IO-nastiness, this will allow you to get on with learning Haskell and not have to worry about mapM_ & friends until you're good and ready.
showTriangle :: [[Int]] -> String
showTriangle triangle = concatMap (\line -> show line ++ "\n") triangle
or
showTriangle = concatMap (\line -> show line ++ "\n")
Then printTriangle is a lot easier:
printTriangle :: Int -> IO ()
printTriangle rows = putStrLn (showTriangle $ pascalTriangle rows)
or
printTriangle = putStrLn . showTriangle . pascalTriangle
If you want to print elements of a list on new lines you shall see this question.
So
printTriangle rows = mapM_ print $ pascalTriangle rows
And
λ> printTriangle 3
[1]
[1,1]
[1,2,1]
Finally, what you're asking for is seems to be mapM_.
Whenever I'm coding in Haskell I always try declare the types of at least the top-level definitions. Not only does it help by documenting your functions, but also makes it easier to catch type errors. So pascalTriangle has the following type:
pascalTriangle :: Int -> [[Int]]
When the compiler sees the lines:
row<-(triangle)
...
where
triangle = pascalTriangle rows
it will infer that triangle has type:
triangle :: [[Int]]
The <- operator expects it's right-hand argument to be a monad. Because you declared your function to work on IO monad, the compiler expected that triangle had the type:
triangle :: IO something
Which clearly does not match type [[Int]]. And that's kind of what the compiler is trying to tell in it's own twisted way.
As others have stated, that style of coding is not idiomatic Haskell. It looks like the kind of code I would produce in my early Haskell days, when I still had an "imperative-oriented" mind. If you try to put aside imperative style of thinking, and open your mind to the functional style, you will find that you can solve most of your problems in a very elegant and tidy fashion.
try the following from the ghci-prompt:
> let {pascal 1 = [1]; pascal n = zipWith (+) (l++[0]) (0:l) where l = pascal (n-1)}
> putStr $ concatMap ((++"\n") . show . pascal) [1..20]
Your code is very unidiomatic Haskell. In Haskell you use higher order function to build other function. That way you can write very concise code.
Here i combine two list lazily using zipWith to produce the next row of pascals triangle pretty much the way you would compute it by hand. Then concatMap is used to produce a printable string of the triangles which is printed by putStr.

Folding across Maybes in Haskell

In an attempt to learn Haskell, I have come across a situation in which I wish to do a fold over a list but my accumulator is a Maybe. The function I'm folding with however takes in the "extracted" value in the Maybe and if one fails they all fail. I have a solution I find kludgy, but knowing as little Haskell as I do, I believe there should be a better way. Say we have the following toy problem: we want to sum a list, but fours for some reason are bad, so if we attempt to sum in a four at any time we want to return Nothing. My current solution is as follows:
import Maybe
explodingFourSum :: [Int] -> Maybe Int
explodingFourSum numberList =
foldl explodingFourMonAdd (Just 0) numberList
where explodingFourMonAdd =
(\x y -> if isNothing x
then Nothing
else explodingFourAdd (fromJust x) y)
explodingFourAdd :: Int -> Int -> Maybe Int
explodingFourAdd _ 4 = Nothing
explodingFourAdd x y = Just(x + y)
So basically, is there a way to clean up, or eliminate, the lambda in the explodingFourMonAdd using some kind of Monad fold? Or somehow currying in the >>=
operator so that the fold behaves like a list of functions chained by >>=?
I think you can use foldM
explodingFourSum numberList = foldM explodingFourAdd 0 numberList
This lets you get rid of the extra lambda and that (Just 0) in the beggining.
BTW, check out hoogle to search around for functions you don't really remember the name for.
So basically, is there a way to clean up, or eliminate, the lambda in the explodingFourMonAdd using some kind of Monad fold?
Yapp. In Control.Monad there's the foldM function, which is exactly what you want here. So you can replace your call to foldl with foldM explodingFourAdd 0 numberList.
You can exploit the fact, that Maybe is a monad. The function sequence :: [m a] -> m [a] has the following effect, if m is Maybe: If all elements in the list are Just x for some x, the result is a list of all those justs. Otherwise, the result is Nothing.
So you first decide for all elements, whether it is a failure. For instance, take your example:
foursToNothing :: [Int] -> [Maybe Int]
foursToNothing = map go where
go 4 = Nothing
go x = Just x
Then you run sequence and fmap the fold:
explodingFourSum = fmap (foldl' (+) 0) . sequence . foursToNothing
Of course you have to adapt this to your specific case.
Here's another possibility not mentioned by other people. You can separately check for fours and do the sum:
import Control.Monad
explodingFourSum xs = guard (all (/=4) xs) >> return (sum xs)
That's the entire source. This solution is beautiful in a lot of ways: it reuses a lot of already-written code, and it nicely expresses the two important facts about the function (whereas the other solutions posted here mix those two facts up together).
Of course, there is at least one good reason not to use this implementation, as well. The other solutions mentioned here traverse the input list only once; this interacts nicely with the garbage collector, allowing only small portions of the list to be in memory at any given time. This solution, on the other hand, traverses xs twice, which will prevent the garbage collector from collecting the list during the first pass.
You can solve your toy example that way, too:
import Data.Traversable
explodingFour 4 = Nothing
explodingFour x = Just x
explodingFourSum = fmap sum . traverse explodingFour
Of course this works only because one value is enough to know when the calculation fails. If the failure condition depends on both values x and y in explodingFourSum, you need to use foldM.
BTW: A fancy way to write explodingFour would be
import Control.Monad
explodingFour x = mfilter (/=4) (Just x)
This trick works for explodingFourAdd as well, but is less readable:
explodingFourAdd x y = Just (x+) `ap` mfilter (/=4) (Just y)

Resources