Related
For a college assignment I am learning Haskell and when reading about the do-notation and sequencing with >>= and >> I came across this behaviour that I did not expect.
[1,2,3] >> [1] -- returns [1,1,1]
Can anyone explain why every element of the first array is replaced by the elements of the second array? It seems like the list is concatenated in some way, while I expected the result of the first expression to be completely ignored, thus I would expect [1] as the result.
Thanks a lot in advance.
The “result” is in this case the values contained in [1,2,3], which are indeed ignored. What >> does not ignore is the context, which for the list monad is the shape (i.e. length) of the list. This can't be ignored, because we must have x >>= pure ≡ x, i.e.
Prelude> [1,2,3] >>= pure
[1,2,3]
Prelude> [1,2,3] >>= \n -> [n]
[1,2,3]
Prelude> [1,2,3] >>= \n -> [1]
[1,1,1]
Prelude> [1,2,3] >>= \_ -> [1]
[1,1,1]
Prelude> [1,2,3] >> [1]
[1,1,1]
An example with length>1 on the RHS:
[1,2,3] >>= \n -> [n, n+10]
[1,11,2,12,3,13]
Prelude> [1,2,3] >>= \n -> [100, 10]
[100,10,100,10,100,10]
Prelude> [1,2,3] >> [100, 10]
[100,10,100,10,100,10]
There are several equivalent ways of writing [1,2,3] >> [1]:
do [1,2,3]
return 1
[ x | _ <- [1,2,3], x <- [1] ]
[ 1 | _ <- [1,2,3] ]
[1,2,3] >>= \_ -> [1]
concatMap (const [1]) [1,2,3]
concat (map (const [1]) [1,2,3])
concat ([1,2,3] $> [1])
It replaces every element of [1..3] with [1] and then collapses it:
concatMap (\_ -> [1]) [1,2,3]
= concat (map (\_ -> [1]) [1,2,3])
= concat [[1],[1],[1]]
= [1,1,1]
It completely ignores the elements of [1,2,3], just using the shape (length). Look what happens if we replace them with undefined:
> do [undefined, undefined, undefined]; return 1
[1,1,1]
The results of the first computation are indeed ignored.
Monads can be seen as generalized nested loops. What you have can be written in pseudocode as
for y in [1,2,3]:
for x in [1]: -- for x in ((\_ -> [1]) y):
yield x
Both y and x are in scope at the innermost level. y's value is indeed ignored.
Still for each y in [1,2,3] each x in [1] is produced, thus defining the overall computation. For lists this means the results produced one by one by the combined computation as a whole are the results produced one by one at the innermost level. Sounds trivial, isn't it.
How exactly this is implemented is an implementational detail. Seeing the lists as data this means splicing the results of the inner computations in place, flattening the list of lists into a one-level list, appending the inner lists together. concatMap is widely known as flatMap in other languages:
[ 1, 2, 3 ]
[1] [1] [1]
-------------------
[ 1, 1, 1 ]
Related answers: Why >> duplicates right-hand side operand , Map and flatMap , How does Monad on list work? , Why list monad combines in that order? , mapM with const functions in Haskell , under the hood reason we can use nested loops in list comprehensions , Generalizing prime pairs in SICP.
I was reading about list monads and encountered:
[1,2] >>= \n -> ['a','b'] >>= \ch -> return (n,ch)
it produces
[(1,'a'),(1,'b'),(2,'a'),(2,'b')]
Here's how I understand it:
Implicit parentheses are:
([1,2] >>= \n -> ['a','b']) >>= (\ch -> return (n,ch))
([1,2] >>= \n -> ['a','b']) should give [('a',1),('b',1),('a',2),('b',2)]
because
instance Monad [] where
return x = [x]
xs >>= f = concat (map f xs) -- this line
fail _ = []
so concat (map f xs) is concat (map (\n -> ['a','b']) [1,2]) which should produce [('a',1),('b',1),('a',2),('b',2)] - quite the opposite of the actual output.
Then I don't understand >>= (\ch -> return (n,ch)) part - I think that n here has no sense. That specific reasoning is flawed, could you please explain how that expression([1,2] >>= \n -> ['a','b'] >>= \ch -> return (n,ch)) is computed step-by-step?
Your implicit parentheses are wrong. The way you have it, the n parameter to the first lambda would not be in scope in the return. It is more like:
([1,2] >>= (\n -> ['a','b'] >>= (\ch -> return (n,ch))))
Which becomes:
concatMap (\n -> concatMap (\ch -> [(n,ch)]) ['a','b']) [1,2]
No, you're using wrong parenthesization. It's nested to the right, so that
[1,2] >>= \n -> ['a','b'] >>= \ch -> return (n,ch)
=
[1,2] >>= (\n -> ['a','b'] >>= (\ch -> return (n,ch) ))
=
do { n <- [1,2]
; do { ch <- ['a','b']
; return (n,ch) }}
=
for n in [1,2]: -- pseudocode
for ch in ['a','b']:
return (n,ch)
=
[ r | n <- [1,2], ch <- ['a','b'], r <- [(n,ch)] ] -- return == (:[])
=
[ (n,ch) | n <- [1,2], ch <- ['a','b'] ]
=
pure (,) <*> [1,2] <*> ['a','b'] -- using list applicative
=
[(1,'a'), (1,'b'), (2,'a'), (2,'b')]
and the innermost list is "spinning" the fastest, like in a car's odometer.
You are absolutely right, with the wrong parenthesization the n binding would make no sense. It is precisely for that reason that it must associate to the right, to make the nested binding possible; for the nested computations are the essence of the monad:
[ foo x | x <- xs ] -- functor : amendable computations
[ bar x y | x <- xs AND y <- ys ] -- applicative : combinable computations
[ baz x y | x <- xs, y <- foo x ] -- monad : reinterpretative computations
(and yes, omitting parentheses in learning material is the root of all evil... not really, but still...)
Implicit parentheses are:
([1,2] >>= \n -> ['a','b']) >>= (\ch -> return (n,ch))
This is wrong. \ has the lowest precedence and thus extends to the end of the expression. So the parentheses are:
[1,2] >>= (\n -> ['a','b'] >>= (\ch -> return (n,ch)))
([1,2] >>= \n -> ['a','b']) should give [('a',1),('b',1),('a',2),('b',2)]
As you can see from the above parenthesization ([1,2] >>= \n -> ['a','b']), isn't actually a subexpression of the given expression. But if it were, its result would be ['a', 'b', 'a', 'b']. n is not actually used anywhere in the expressions ['a', 'b'], so there's no way the numbers could appear in the result.
Then I don't understand >>= (\ch -> return (n,ch)) part - I think that n here has no sense.
Given your parenthesization n would indeed be undefined there. However given the proper parenthesization it should be clear where n comes from: We're still inside the \n -> ... function, so n still refers to the argument of that function, namely the current element of the [1, 2] list.
You're wrong about the semantics of concat (map (\n -> ['a','b']) [1,2]). I've done a step by step evaluation of it below.
concat (map (\n -> ['a','b']) [1,2])
concat [(\n -> ['a','b']) 1, (\n -> ['a','b']) 2]
concat [['a','b'], ['a','b']]
['a','b','a','b']
The last bind is what is used to actually make it a list of tuples.
So what I have so far is something like this:
combs :: [[Char]]
combs = [[i] ++ [j] ++ [k] ++ [l] | i <- x, j <- x, k <- x, l <- x]
where x = "abc"
So this is the working function for n = 4, is there any way to make this work for an arbitrary number of generators? I could program in for n = 1, 2, 3 etc.. but ideally need it to work for any given n. For reference, x is just an arbitrary string of unique characters. I'm struggling to think of a way to somehow extract it to work for n generators.
You can use replicateM:
replicateM :: Applicative m => Int -> m a -> m [a]
E.g.:
generate :: Num a => Int -> [[a]]
generate = flip replicateM [1,2,3]
to generate all possiible lists of a given length and consisting of elements 1..3.
As far as I know, you can not construct list comprehension with an arbitrary number of generators, but usually if you do something with arbitrary depth, recursion is the way to do it.
So we have to think of solving this, in terms of itself. If you want all possible strings that can be generated with the characters in x. In case n = 0, we can generate exactly one string: the empty string.
combs 0 = [""]
so a list with one element [].
Now in case we want to generate strings with one characters, we can of course simply return x:
combs 1 = x
and now the question is what to do in case n > 1. In that case we can obtain all the strings with length n-1, and and for each such string, and each such character in x, produce a new string. Like:
combs n = [ (c:cs) | c <- x, cs <- combs (n-1) ]
Note that this makes the second case (n = 1) redundant. We can pick a character c from x, and prepend that to the empty string. So a basic implementation is:
combs :: Int -> [[Char]]
combs 0 = [""]
combs n = [(c:cs) | c <- x, cs <- combs (n-1)]
where x = "abc"
Now we can still look for improvements. List comprehensions are basically syntactical sugar for the list monad. So we can use liftA2 here:
import Control.Applicative(liftA2)
combs :: Int -> [[Char]]
combs 0 = [""]
combs n = liftA2 (:) x (combs (n-1))
where x = "abc"
we probably also want to make the set of characters a parameter:
import Control.Applicative(liftA2)
combs :: [Char] -> Int -> [[Char]]
combs _ 0 = [""]
combs x n = liftA2 (:) x (combs (n-1))
and we do not have to restrict us to characters, we can produce a certesian power for all possible types:
import Control.Applicative(liftA2)
combs :: [a] -> Int -> [[a]]
combs _ 0 = [[]]
combs x n = liftA2 (:) x (combs (n-1))
First I would translate the comprehension as a monadic expression.
x >>= \i -> x >>= \j -> x >>= \k -> x >>= \l -> return [i,j,k,l]
With n = 4 we see we have 4 x's, and generally will have n x's. Therefore, I am thinking about a list of x's of length n.
[x,x,x,x] :: [[a]]
How might we go from [x,x,x,x] to the monadic expression? A first good guess is foldr, since we want to do something with each element of the list. Particularly, we want to take an element from each x and form a list with these elements.
foldr :: (a -> b -> b) -> b -> [a] -> b
-- Or more accurately for our scenario:
foldr :: ([a] -> [[a]] -> [[a]]) -> [[a]] -> [[a]] -> [[a]]
There are two terms to come up with for foldr, which I will call f :: [a] -> [[a]] -> [[a]] and z :: [[a]]. We know what foldr f z [x,x,x,x] is:
foldr f z [x,x,x,x] = f x (f x (f x (f x z)))
If we add parentheses to the earlier monadic expression, we have this:
x >>= \i -> (x >>= \j -> (x >>= \k -> (x >>= \l -> return [i,j,k,l])))
You can see how the two expressions are looking similar. We should be able to find an f and z to make them the same. If we choose f = \x a -> x >>= \x' -> a >>= \a' -> return (x' : a') we get:
f x (f x (f x (f x z)))
= (\x a -> a >>= \a' -> x >>= \x' -> return (x' : a')) x (f x (f x (f x z)))
= f x (f x (f x z)) >>= \a' -> x >>= \x' -> return (x' : a')
= f x (f x (f x z)) >>= \a' -> x >>= \l -> return (l : a')
= (f x (f x z) >>= \a' -> x >>= \k -> return (k : a')) >>= \a' -> x >>= \l -> return (l : a')
= f x (f x z) >>= \a' -> x >>= \k -> x >>= \l -> return (l : k : a')
Note that I have reversed the order of i,j,k,l to l,k,j,i but in context of finding combinations, this should be irrelevant. We could try a' ++ [x'] instead if it was really of concern.
The last step is because (a >>= \b -> c) >>= \d -> e is the same as a >>= \b -> c >>= \d -> e (when accounting for variable hygiene) and return a >>= \b -> c is the same as (\b -> c) a.
If we keep unfolding this expression, eventually we will reach z >>= \a' -> … on the front. The only choice that makes sense here then is z = [[]]. This means that foldr f z [] = [[]] which may not be desirable (preferring [] instead). Instead, we might use foldr1 (for non-empty lists, and we might use Data.NonEmpty) or we might add a separate clause for empty lists to combs.
Looking at f = \x a -> x >>= \x' -> a >>= \a' -> return (x' : a') we might realise this helpful equivalence: a >>= \b -> return (c b) = c <$> a. Therefore, f = \x a -> x >>= \x' -> (x' :) <$> a. Then also, a >>= \b -> c (g b) = g <$> a >>= \b -> c and so f = (:) <$> x >>= \x' -> x' <$> a. Finally, a <*> b = a >>= \x -> x <$> b and so f = (:) <$> x <*> a.
The official implementation of sequenceA for lists is foldr (\x a -> (:) <$> x <*> a) (pure []), exactly what we came up with here too. This can be further shortened as foldr (liftA2 (:)) (pure []) but there is possibly some optimisation difference that made the implementors not choose this.
Last step is to merely come up with a list of n x's. This is just replicate replicate n x. There happens to be a function which does both replication and sequencing, called replicateM replicateM n x.
I'm having a problem with understanding how F# works. I come from C# and I think that I'm trying to make F# work like C#. My biggest problem is returning values in the correct format.
Example:
Let's say I have function that takes a list of integers and an integer.
Function should print a list of indexes where values from list match passed integer.
My code:
let indeks myList n = myList |> List.mapi (fun i x -> if x=n then i else 0);;
indeks [0..4] 3;;
However it returns:
val it : int list = [0; 0; 0; 3; 0]
instead of just [3] as I cannot ommit else in that statement.
Also I have targeted signature of -> int list -> int -> int list and I get something else.
Same goes for problem no. 2 where I want to provide an integer and print every number from 0 to this integer n times (where n is the iterated value):
example:
MultiplyValues 3;;
output: [1;2;2;3;3;3]
Best I could do was to create list of lists.
What am I missing when returning elements?
How do I add nothing to the return
example: if x=n then n else AddNothingToTheReturn
Use List.choose:
let indeks lst n =
lst
|> List.mapi (fun i s -> if s = n then Some i else None)
|> List.choose id
Sorry, I didn't notice that you had a second problem too. For that you can use List.collect:
let f (n : int) : list<int> =
[1 .. n]
|> List.collect (fun s -> List.init s (fun t -> s))
printfn "%A" (f 3) // [1; 2; 2; 3; 3; 3]
Please read the documentation for List.collect for more information.
EDIT
Following s952163's lead, here is another version of the first solution without the Option type:
let indeks (lst : list<int>) (n : int) : list<int> =
lst
|> List.fold (fun (s, t) u -> s + 1, (if u = n then (s :: t) else t)) (0, [])
|> (snd >> List.rev)
This one traverses the original list once, and the (potentially much shorter) newly formed list once.
The previous answer is quite idiomatic. Here's one solution that avoids the use of Option types and id:
let indeks2 lst n =
lst
|> List.mapi (fun i x -> (i,x))
|> List.filter (fun x -> (fst x) % n = 0 )
|> List.map snd
You can modify the filter function to match your needs.
If you plan to generate lots of sequences it might be a good idea to explore Sequence (list) comprehensions:
[for i in 1..10 do
yield! List.replicate i i]
If statements are an expression in F# and they return a value. In this case both the IF and ELSE branch must return the same type of value. Using Some/None (Option type) gets around this. There are some cases where you can get away with just using If.
I think I do understand the list monad but then I found I am not. Here is the story.
Given list m and function k
> let m = [1..10]
> :t m
m :: [Integer]
> let k = replicate 2
> :t k
k :: a -> [a]
Playing with bind >>= give what I expect
> :t (>>=)
(>>=) :: Monad m => m a -> (a -> m b) -> m b
> :t m >>= k
m >>= k :: [Integer]
> m >>= k
[1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10]
but for >>
Expected (from experiencing with IO monad, everything on left side would be discarded)
m >> m
[1,2,3,4,5,6,7,8,9,10]
Got
> :t (>>)
(>>) :: Monad m => m a -> m b -> m b
:t m >> m
m >> m :: [Integer]
> m >> m
[1,2,3,4,5,6,7,8,9,10,1,2,3,4,5 ... 9,10] -- truncated, real output is 100 elements
Please explain why >> is not behave like I expected (of course I must have misunderstanding) and what is the correct way to interpret >> ?
(>>) discards values from its first argument, but not effects. In this case it might be easier to see if you use lists with different types:
λ> "ab" >> [1,2,3,4]
[1,2,3,4,1,2,3,4]
Note how the values of the first list aren't used at all.
Remember the definition of (>>): a >> b = a >>= (\_ -> b). So this turns into "ab" >>= (\_ -> [1,2,3,4]), i.e. concat (map (\_ -> [1,2,3,4]) ['a','b']), i.e. concat [[1,2,3,4],[1,2,3,4]] (also, [i | _ <- "ab", i <- [1,2,3,4]]).
With [], (>>=) means something like "for each". The function on the right gets as an argument each value on the left. So (>>), which discards values, still means "for each" -- but this time it can't use the value, so it just means "the elements of the second list, repeated as many times as there are elements in the first list".
foo >> bar is the same as foo >>= \_ -> bar. So in the case of IO it executes the left action, ignoring the return value of that action, and then executes the right action. In the case of lists it maps over each element in the left list, ignoring the value of each elements, and inserts the right list at each point.
Another way to look at it is that >>= for lists is the same as flip concatMap, >> is the same as flip (concatMap . const).