Converting `do notation` to >>= v. map - haskell

Given the following do notation code:
do
a <- return 1
b <- [10,20]
return $ a+b
Is there a more idiomatic conversion:
ghci> return 1 >>= (\x -> map (+x) [10, 20])
[11,21]
versus
ghci> return 1 >>= (\x -> [10, 20] >>= (\y -> [y+x]))
[11,21]

do notation maps to monadic functions, so strictly you'd write
return 1 >>= (\a -> [10, 20] >>= (\b -> return $ a+b ))
Now, you can replace that >>= … return by just fmap
return 1 >>= (\x -> fmap (\y -> x+y) [10, 20])
and use sections, and scrap that constant 1 right into the function
fmap (1+) [10, 20]
Alternatively, if you really want to take your first summand from a list, I'd recommend to use liftM2:
liftM2 (+) [1] [10, 20]
A bit more idiomatic than this, and with the same results, is the Applicative instance of lists:
(+) <$> [1] <*> [10, 20]

Related

Haskell: do notation and return in Monads

Suppose I have following code
do {x <- (Just 3); y <- (Just 5); return (x:y:[])}
Which outputs Just [3,5]
How does haskell know that output value should be in Maybe monad? I mean return could output [[3, 5]].
do {x <- (Just 3); y <- (Just 5); return (x:y:[])}
desugars to
Just 3 >>= \x -> Just 5 >>= \y -> return $ x:y:[]
Since the type of >>= is Monad m => m a -> (a -> m b) -> m b and per argument Just 3 (alternatively Just 5) we have m ~ Maybe, the return type of the expression must be some Maybe type.
There is a possibility to make this return [[3, 5]] using something called natural transformations from category theory. Because there exists a natural transformation from Maybe a to [a], namely
alpha :: Maybe a -> [a]
alpha Nothing = []
alpha (Just a) = [a]
we have that your desired function is simply the natural transformation applied to the result:
alpha (Just 3 >>= \x -> Just 5 >>= \y -> return $ x:y:[])
-- returns [[3, 5]]
Since this is a natural transformation, you can also apply alpha first and your function second:
alpha (Just 3) >>= \x -> alpha (Just 5) >>= \y -> return $ x:y:[]
-- returns [[3, 5]]
As #duplode pointed out, you can find alpha in the package Data.Maybe as maybeToList.

Idiomatic way to sum a list of Maybe Int in haskell

Is there a more idiomatic way to implement the following? I feel like I'm missing a way to get rid of the lambda, but couldn't figure out a way to convert it to point-free. Maybe there is another non-applicative way as well that is more straight forward?
import Data.Maybe
import Control.Applicative
foldl (\x y -> pure (+) <*> x <*> y) (Just 0) [Just 3, Just 4]
-- Just 7
foldl (\x y -> pure (+) <*> x <*> y) (Just 0) [Just 3, Just 4, Nothing]
-- Nothing
I'd just use sequence from Control.Monad:
> fmap sum $ sequence [Just 3, Just 4]
Just 7
> fmap sum $ sequence [Just 3, Just 4, Nothing]
Nothing
For the point-free form:
sumMaybe :: Num a => [Maybe a] -> Maybe a
sumMaybe = fmap sum . sequence
The most direct way to eliminate the lambda is to use liftA2; it's exactly the code you wrote
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
liftA2 f x y = pure f <*> x <*> y
foldl (liftA2 (+)) (Just 0) [Just 1, Just 2]
then we have a few choices for how to propagate the errors. This code has it that any Nothing will lead to a total failure. We can do that in two steps like #bhekilr suggested using sequence.
sum <$> sequence [Just 1, Just 2] sum <$> sequence [Just 1, Nothing]
Just (sum [1,2]) sum <$> Nothing
Just 3 Nothing
We can also use the fact that (+) induces a Monoid on the values in order to just "ignore" Nothings. Most literally that would be
import Data.Monoid
getSum $ foldMap (maybe mempty Sum) [Just 1, Just 2, Nothing]
-- equivalent to, but faster than
getSum . mconcat . map (maybe mempty Sum) $ [Just 1, Just 2, Nothing]
getSum . mconcat $ [Sum 1, Sum 2, Sum 0]
3
But we can also use catMaybe from Data.Monoid to do it in two steps
sum . catMaybes $ [Just 1, Just 2, Nothing]
sum [1, 2]
3
I think foldM works well here.
import Control.Monad
sumMay = foldM (fmap . (+)) 0
I think it's the clearest as it maps (Ba duh duh ching) to what you'd do in pure code.
You can lift the (+) in the Maybe Monad with:
input> fold (liftM2 (+)) (Just 0) [Just 1, Just 2]
Just 3
input> fold (liftM2 (+)) (Just 0) [Just 1, Just 2, Nothing]
Nothing
import Data.Maybe
import Data.List
sumMaybes = sum . catMaybes

Nested loop equivalent

I want to do a list of concatenations in Haskell.
I have [1,2,3] and [4,5,6]
and i want to produce [14,15,16,24,25,26,34,35,36].
I know I can use zipWith or sth, but how to do equivalent of:
foreach in first_array
foreach in second_array
I guess I have to use map and half curried functions, but can't really make it alone :S
You could use list comprehension to do it:
[x * 10 + y | x <- [1..3], y <- [4..6]]
In fact this is a direct translation of a nested loop, since the first one is the outer / slower index, and the second one is the faster / inner index.
You can exploit the fact that lists are monads and use the do notation:
do
a <- [1, 2, 3]
b <- [4, 5, 6]
return $ a * 10 + b
You can also exploit the fact that lists are applicative functors (assuming you have Control.Applicative imported):
(+) <$> (*10) <$> [1,2,3] <*> [4,5,6]
Both result in the following:
[14,15,16,24,25,26,34,35,36]
If you really like seeing for in your code you can also do something like this:
for :: [a] -> (a -> b) -> [b]
for = flip map
nested :: [Integer]
nested = concat nested_list
where nested_list =
for [1, 2, 3] (\i ->
for [4, 5, 6] (\j ->
i * 10 + j
)
)
You could also look into for and Identity for a more idiomatic approach.
Nested loops correspond to nested uses of map or similar functions. First approximation:
notThereYet :: [[Integer]]
notThereYet = map (\x -> map (\y -> x*10 + y) [4, 5, 6]) [1, 2, 3]
That gives you nested lists, which you can eliminate in two ways. One is to use the concat :: [[a]] -> [a] function:
solution1 :: [Integer]
solution1 = concat (map (\x -> map (\y -> x*10 + y) [4, 5, 6]) [1, 2, 3])
Another is to use this built-in function:
concatMap :: (a -> [b]) -> [a] -> [b]
concatMap f xs = concat (map f xs)
Using that:
solution2 :: [Integer]
solution2 = concatMap (\x -> map (\y -> x*10 + y) [4, 5, 6]) [1, 2, 3]
Other people have mentioned list comprehensions and the list monad, but those really bottom down to nested uses of concatMap.
Because do notation and the list comprehension have been said already. The only other option I know is via the liftM2 combinator from Control.Monad. Which is the exact same thing as the previous two.
liftM2 (\a b -> a * 10 + b) [1..3] [4..6]
The general solution of the concatenation of two lists of integers is this:
concatInt [] xs = xs
concatInt xs [] = xs
concatInt xs ys = [join x y | x <- xs , y <- ys ]
where
join x y = firstPart + secondPart
where
firstPart = x * 10 ^ lengthSecondPart
lengthSecondPart = 1 + (truncate $ logBase 10 (fromIntegral y))
secondPart = y
Example: concatInt [1,2,3] [4,5,6] == [14,15,16,24,25,26,34,35,36]
More complex example:
concatInt [0,2,10,1,100,200] [24,2,999,44,3] == [24,2,999,44,3,224,22,2999,244,23,1024,102,10999,1044,103,124,12,1999,144,13,10024,1002,100999,10044,1003,20024,2002,200999,20044,2003]

Best practice how to evaluate a list of Maybes

i am looking for a function which takes a function (a -> a -> a) and a list of [Maybe a] and returns Maybe a. Hoogle gave me nothing useful. This looks like a pretty common pattern, so i am asking if there is a best practice for this case?
>>> f (+) [Just 3, Just 3]
Just 6
>>> f (+) [Just 3, Just 3, Nothing]
Nothing
Thanks in advance, Chris
You should first turn the [Maybe a] into a Maybe [a] with all the Just elements (yielding Nothing if any of them are Nothing).
This can be done using sequence, using Maybe's Monad instance:
GHCi> sequence [Just 1, Just 2]
Just [1,2]
GHCi> sequence [Just 1, Just 2, Nothing]
Nothing
The definition of sequence is equivalent to the following:
sequence [] = return []
sequence (m:ms) = do
x <- m
xs <- sequence ms
return (x:xs)
So we can expand the latter example as:
do x <- Just 1
xs <- do
y <- Just 2
ys <- do
z <- Nothing
zs <- return []
return (z:zs)
return (y:ys)
return (x:xs)
Using the do-notation expression of the monad laws, we can rewrite this as follows:
do x <- Just 1
y <- Just 2
z <- Nothing
return [x, y, z]
If you know how the Maybe monad works, you should now understand how sequence works to achieve the desired behaviour. :)
You can then compose this with foldr using (<$>) (from Control.Applicative; equivalently, fmap or liftM) to fold your binary function over the list:
GHCi> foldl' (+) 0 <$> sequence [Just 1, Just 2]
Just 3
Of course, you can use any fold you want, such as foldr, foldl1 etc.
As an extra, if you want the result to be Nothing when the list is empty, and thus be able to omit the zero value of the fold without worrying about errors on empty lists, then you can use this fold function:
mfoldl1' :: (MonadPlus m) => (a -> a -> a) -> [a] -> m a
mfoldl1' _ [] = mzero
mfoldl1' f (x:xs) = return $ foldl' f x xs
and similarly for foldr, foldl, etc. You'll need to import Control.Monad for this.
However, this has to be used slightly differently:
GHCi> mfoldl1' (+) =<< sequence [Just 1, Just 2]
Just 3
or
GHCi> sequence [Just 1, Just 2] >>= mfoldl1' (+)
Just 3
This is because, unlike the other folds, the result type looks like m a instead of a; it's a bind rather than a map.
As I understand it, you want to get the sum of a bunch of maybes or Nothing if any of them are Nothing. This is actually pretty simple:
maybeSum = foldl1 (liftM2 (+))
You can generalize this to something like:
f :: Monad m => (a -> a -> a) -> [m a] -> m a
f = foldl1 . liftM2
When used with the Maybe monad, f works exactly the way you want.
If you care about empty lists, you can use this version:
f :: MonadPlus m => (a -> a -> a) -> [m a] -> m a
f _ [] = mzero
f fn (x:xs) = foldl (liftM2 fn) x xs
What about something as simple as:
λ Prelude > fmap sum . sequence $ [Just 1, Just 2]
Just 3
λ Prelude > fmap sum . sequence $ [Just 1, Just 2, Nothing]
Nothing
Or, by using (+):
λ Prelude > fmap (foldr (+) 0) . sequence $ [Just 1, Just 2]
Just 3
λ Prelude > fmap (foldr (+) 0) . sequence $ [Just 1, Just 2, Nothing]
Nothing
So, maybeSum = fmap sum . sequence.

Haskell function application and currying

I am always interested in learning new languages, a fact that keeps me on my toes and makes me (I believe) a better programmer. My attempts at conquering Haskell come and go - twice so far - and I decided it was time to try again. 3rd time's the charm, right?
Nope. I re-read my old notes... and get disappointed :-(
The problem that made me lose faith last time, was an easy one: permutations of integers.
i.e. from a list of integers, to a list of lists - a list of their permutations:
[int] -> [[int]]
This is in fact a generic problem, so replacing 'int' above with 'a', would still apply.
From my notes:
I code it first on my own, I succeed. Hurrah!
I send my solution to a good friend of mine - Haskell guru, it usually helps to learn from gurus - and he sends me this, which I am told, "expresses the true power of the language, the use of generic facilities to code your needs". All for it, I recently drank the kool-aid, let's go:
permute :: [a] -> [[a]]
permute = foldr (concatMap.ins) [[]]
where ins x [] = [[x]]
ins x (y:ys) = (x:y:ys):[ y:res | res <- ins x ys]
Hmm.
Let's break this down:
bash$ cat b.hs
ins x [] = [[x]]
ins x (y:ys) = (x:y:ys):[ y:res | res <- ins x ys]
bash$ ghci
Prelude> :load b.hs
[1 of 1] Compiling Main ( b.hs, interpreted )
Ok, modules loaded: Main.
*Main> ins 1 [2,3]
[[1,2,3],[2,1,3],[2,3,1]]
OK, so far, so good. Took me a minute to understand the second line of "ins", but OK:
It places the 1st arg in all possible positions in the list. Cool.
Now, to understand the foldr and concatMap. in "Real world Haskell", the DOT was explained...
(f . g) x
...as just another syntax for...
f (g x)
And in the code the guru sent, DOT was used from a foldr, with the "ins" function as the fold "collapse":
*Main> let g=concatMap . ins
*Main> g 1 [[2,3]]
[[1,2,3],[2,1,3],[2,3,1]]
OK, since I want to understand how the DOT is used by the guru, I try the equivalent expression according to the DOT definition, (f . g) x = f (g x) ...
*Main> concatMap (ins 1 [[2,3]])
<interactive>:1:11:
Couldn't match expected type `a -> [b]'
against inferred type `[[[t]]]'
In the first argument of `concatMap', namely `(ins 1 [[2, 3]])'
In the expression: concatMap (ins 1 [[2, 3]])
In the definition of `it': it = concatMap (ins 1 [[2, 3]])
What!?! Why?
OK, I check concatMap's signature, and find that it needs a lambda and a list, but that's
just a human thinking; how does GHC cope? According to the definition of DOT above...
(f.g)x = f(g x),
...what I did was valid, replace-wise:
(concatMap . ins) x y = concatMap (ins x y)
Scratching head...
*Main> concatMap (ins 1) [[2,3]]
[[1,2,3],[2,1,3],[2,3,1]]
So... The DOT explanation was apparently
too simplistic... DOT must be somehow clever enough to understand
that we in fact wanted "ins" to get curri-ed away and "eat" the first
argument - thus becoming a function that only wants to operate on [t]
(and "intersperse" them with '1' in all possible positions).
But where was this specified? How did GHC knew to do this, when we invoked:
*Main> (concatMap . ins) 1 [[2,3]]
[[1,2,3],[2,1,3],[2,3,1]]
Did the "ins" signature somehow conveyed this... "eat my first argument" policy?
*Main> :info ins
ins :: t -> [t] -> [[t]] -- Defined at b.hs:1:0-2
I don't see nothing special - "ins" is a function that takes a 't',
a list of 't', and proceeds to create a list with all "interspersals". Nothing about "eat your first argument and curry it away".
So there... I am baffled. I understand (after an hour of looking at the code!) what goes on, but... God almighty... Perhaps GHC makes attempts to see how many arguments it can "peel off"?
let's try with no argument "curried" into "ins",
oh gosh, boom,
let's try with one argument "curried" into "ins",
yep, works,
that must be it, proceed)
Again - yikes...
And since I am always comparing the languages I am learning with what I already know, how would "ins" look in Python?
a=[2,3]
print [a[:x]+[1]+a[x:] for x in xrange(len(a)+1)]
[[1, 2, 3], [2, 1, 3], [2, 3, 1]]
Be honest, now... which is simpler?
I mean, I know I am a newbie in Haskell, but I feel like an idiot... Looking at 4 lines of code for an hour, and ending up assuming that the compiler... tries various interpretations until it finds something that "clicks"?
To quote from Lethal weapon, "I am too old for this"...
(f . g) x = f (g x)
This is true. You concluded from that that
(f . g) x y = f (g x y)
must also be true, but that is not the case. In fact, the following is true:
(f . g) x y = f (g x) y
which is not the same.
Why is this true? Well (f . g) x y is the same as ((f . g) x) y and since we know that (f . g) x = f (g x) we can reduce that to (f (g x)) y, which is again the same as f (g x) y.
So (concatMap . ins) 1 [[2,3]] is equivalent to concatMap (ins 1) [[2,3]]. There is no magic going on here.
Another way to approach this is via the types:
. has the type (b -> c) -> (a -> b) -> a -> c, concatMap has the type (x -> [y]) -> [x] -> [y], ins has the type t -> [t] -> [[t]]. So if we use concatMap as the b -> c argument and ins as the a -> b argument, then a becomes t, b becomes [t] -> [[t]] and c becomes [[t]] -> [[t]] (with x = [t] and y = [t]).
So the type of concatMap . ins is t -> [[t]] -> [[t]], which means a function taking a whatever and a list of lists (of whatevers) and returning a list of lists (of the same type).
I'd like to add my two cents. The question and answer make it sound like . is some magical operator that does strange things with re-arranging function calls. That's not the case. . is just function composition. Here's an implementation in Python:
def dot(f, g):
def result(arg):
return f(g(arg))
return result
It just creates a new function which applies g to an argument, applies f to the result, and returns the result of applying f.
So (concatMap . ins) 1 [[2, 3]] is saying: create a function, concatMap . ins, and apply it to the arguments 1 and [[2, 3]]. When you do concatMap (ins 1 [[2,3]]) you're instead saying, apply the function concatMap to the result of applying ins to 1 and [[2, 3]] - completely different, as you figured out by Haskell's horrendous error message.
UPDATE: To stress this even further. You said that (f . g) x was another syntax for f (g x). This is wrong! . is just a function, as functions can have non-alpha-numeric names (>><, .., etc., could also be function names).
You're overthinking this problem. You can work it all out using simple equational reasoning. Let's try it from scratch:
permute = foldr (concatMap . ins) [[]]
This can be converted trivially to:
permute lst = foldr (concatMap . ins) [[]] lst
concatMap can be defined as:
concatMap f lst = concat (map f lst)
The way foldr works on a list is that (for instance):
-- let lst = [x, y, z]
foldr f init lst
= foldr f init [x, y, z]
= foldr f init (x : y : z : [])
= f x (f y (f z init))
So something like
permute [1, 2, 3]
becomes:
foldr (concatMap . ins) [[]] [1, 2, 3]
= (concatMap . ins) 1
((concatMap . ins) 2
((concatMap . ins) 3 [[]]))
Let's work through the first expression:
(concatMap . ins) 3 [[]]
= (\x -> concatMap (ins x)) 3 [[]] -- definition of (.)
= (concatMap (ins 3)) [[]]
= concatMap (ins 3) [[]] -- parens are unnecessary
= concat (map (ins 3) [[]]) -- definition of concatMap
Now ins 3 [] == [3], so
map (ins 3) [[]] == (ins 3 []) : [] -- definition of map
= [3] : []
= [[3]]
So our original expression becomes:
foldr (concatMap . ins) [[]] [1, 2, 3]
= (concatMap . ins) 1
((concatMap . ins) 2
((concatMap . ins) 3 [[]]))
= (concatMap . ins) 1
((concatMap . ins) 2 [[3]]
Let's work through
(concatMap . ins) 2 [[3]]
= (\x -> concatMap (ins x)) 2 [[3]]
= (concatMap (ins 2)) [[3]]
= concatMap (ins 2) [[3]] -- parens are unnecessary
= concat (map (ins 2) [[3]]) -- definition of concatMap
= concat (ins 2 [3] : [])
= concat ([[2, 3], [3, 2]] : [])
= concat [[[2, 3], [3, 2]]]
= [[2, 3], [3, 2]]
So our original expression becomes:
foldr (concatMap . ins) [[]] [1, 2, 3]
= (concatMap . ins) 1 [[2, 3], [3, 2]]
= (\x -> concatMap (ins x)) 1 [[2, 3], [3, 2]]
= concatMap (ins 1) [[2, 3], [3, 2]]
= concat (map (ins 1) [[2, 3], [3, 2]])
= concat [ins 1 [2, 3], ins 1 [3, 2]] -- definition of map
= concat [[[1, 2, 3], [2, 1, 3], [2, 3, 1]],
[[1, 3, 2], [3, 1, 2], [3, 2, 1]]] -- defn of ins
= [[1, 2, 3], [2, 1, 3], [2, 3, 1],
[1, 3, 2], [3, 1, 2], [3, 2, 1]]
Nothing magical here. I think you may have been confused because it's easy to assume that concatMap = concat . map, but this is not the case. Similarly, it may seem like concatMap f = concat . (map f), but this isn't true either. Equational reasoning will show you why.

Resources