What does "<-" mean? [duplicate] - haskell

This question already has answers here:
Replace a 3 parameter list-comprehension by using map, concat
(3 answers)
Closed 3 years ago.
In this tutorial http://learnyouahaskell.com/starting-out the author writes this piece of code.
boomBangs xs = [ if x < 10 then "BOOM!" else "BANG!" | x <- xs, odd x]
And then later executes it like this
boomBangs[7..13]
And my question is, what does the "<-" operator do? To me this seems like it would cause recursive behavior, since I am referencing what looks to me like a function inside a function, or perhaps defining how to create a list comprehension.
Searching around I found this explanation by chi on a different question:
"x <- action runs the IO action, gets its result, and binds it to x"
Is the "<-" in the question linked above different to the "<-" used in the code I copied above? Does xs run inside xs? I'd be grateful if someone could explain to me what's going on here.

Your list comprehension is in essence just syntactical sugar for:
import Control.Monad(guard)
boomBangs :: Integral i => [i] -> [String]
boomBangs xs = do
x <- xs
guard (odd x)
return (if x < 10 then "BOOM!" else "BANG!")
This is thus a do expression [Haskell report], and as the report says, it is syntactical sugar. It is syntactical sugar for:
boomBangs xs = xs >>= \x -> (guard (odd x) >> return (if x < 10 then "BOOM!" else "BANG!"))
For a list the Monad instance is defined as:
instance Monad [] where
(>>=) = flip concatMap
return x = [x]
Furthermore the guard is defined as:
guard :: Monad m => Bool -> m ()
guard True = pure ()
guard False = empty
and the default implementation of (>>) is:
(>>) :: Monad m => m a -> m b -> m b
(>>) u v = u >>= \_ -> v
So the boomBangs is basically implemented as:
boomBangs xs = concatMap (\x -> (guard (odd x) >>= \_ -> [if x < 10 then "BOOM!" else "BANG!"])) xs
= concatMap (\x -> concatMap (\_ -> [if x < 10 then "BOOM!" else "BANG!"]) guard (odd x)) xs
Since for a list, the guard can be specialized to:
-- guard for the Monad []
guard :: Bool -> [()]
guard True = [()]
guard False = []
It thus means that if the guard gets a True, it returns a singleton list, and for False an empty list. This thus means that given the guard holds, the concatMap (\_ -> [if x < 10 then "BOOM!" else "BANG!"]) will return the content in the [if x < 10 then "BOOM!" else "BANG!"], if the guard fails, it will return an empty list. The guard acts thus as some sort of filter.
So now what is the x <-. If we look at how the do-expressions are desugared, an x <- foo, corresponds to the foo >>= \x -> ....
For list comprehensions, x <- ... acts as some sort of "enumerator": it will enumerate over all elements in the list, and x will each time obtain one of the elements in the list to do further processing.

Related

How does the bind operator get invoked multiple times

First I would like to apologize if I am not asking the correct question. I realize that there are some fundamental concepts that I don't quite understand about Monads and the bind operator which is making it difficult to formulate my question. I am having a hard time wrapping my head around how the following code is creating a list of tuples.
ordPairs :: Ord a => [a] -> [(a, a)]
ordPairs xs =
xs >>= \x1 ->
xs >>= \x2 ->
if x1 < x2 then [(x1, x2)] else []
main = print $ ordPairs [1, 2, 4, 6, 7, 8, 3, 4, 5, 6, 2, 9, 7, 8, 45, 4]
I understand the type declaration states that it returns a list of tuples [(a, a)]. What I can't figure out is how is this code "looping" through each item in the list? Looking at this as a beginner it looks as if it only passes the first and second item forward x1 and x2 and then ends with the if then else expression. Is this code being desugared into multiple iterations and building the list under the hood? I guess what I am asking is how is this code iterating through each item in the list and building a list of tuples at the end?
It might help to understand "where the parentheses are". The right-hand side of the ordPairs definitions is parsed like this:
xs >>= (\x1 -> xs >>= (\x2 -> if x1 < x2 then [(x1, x2)] else []))
As you can see here, the if-then-else expression does not stand alone, it's actually the body of an anonymous function:
\x2 -> if x1 < x2 then [(x1, x2)] else []
which can, obviously, be invoked multiple times for different values of x2. What invokes it? Well, the second >>= operator, of course. The "outer" loop works similarly, with the first >>= operator invoking another anonymous function multiple times:
\x1 -> xs >>= (\x2 -> ...)
For this example, you could replace the >>= operator with your own custom bind function. Note that it's just a plain function. There's no special desugaring or secret iterating going on. The function itself does the iterating using recursion:
bind :: [a] -> (a -> [b]) -> [b]
bind (x:xs) f = f x ++ bind xs f
bind [] _ = []
You could also write bind like this, if you prefer:
bind xs f = concatMap f xs
-- or even `bind = flip concatMap`, as per #WillemVanOnsem's comment
Or as a list comprehension.
bind xs f = [y | x <- xs, y <- f x]
This last one is the actual definition of the >>= operator for the list monad. See GHC/Base.hs.
With any of these definitions, the following will work just like your original:
bind :: [a] -> (a -> [b]) -> [b]
bind (x:xs) f = f x ++ bind xs f
bind [] _ = []
ordPairs :: Ord a => [a] -> [(a, a)]
ordPairs xs =
xs `bind` \x1 ->
xs `bind` \x2 ->
if x1 < x2 then [(x1, x2)] else []
main = print $ ordPairs [1,2,4,6,7,8,4,5,6,2,9,7,8,45,4]

Is there any terminating fold in Haskell?

I need some kind of fold which can terminate if I already have the data I want.
For example I need to find first 3 numbers which are greater than 5. I decided to use Either for termination and my code looks like this:
terminatingFold :: ([b] -> a -> Either [b] [b]) -> [a] -> [b]
terminatingFold f l = reverse $ either id id $ fold [] l
where fold acc [] = Right acc
fold acc (x:xs) = f acc x >>= flip fold xs
first3NumsGreater5 acc x =
if length acc >= 3
then Left acc
else Right (if x > 5 then (x : acc) else acc)
Are there some more clever/generic approaches?
The result of your function is a list, and it would be desirable if it were produced lazily, that is, extracting one item from the result should only require evaluating the input list up until the item is found there.
Unfolds are under-appreciated for these kinds of tasks. Instead of focusing on "consuming" the input list, let's think of it as a seed from which (paired with some internal accumulator) we can produce the result, element by element.
Let's define a Seed type that contains a generic accumulator paired with the as-yet unconsumed parts of the input:
{-# LANGUAGE NamedFieldPuns #-}
import Data.List (unfoldr)
data Seed acc input = Seed {acc :: acc, pending :: [input]}
Now let's reformulate first3NumsGreater5 as a function that either produces the next output element from the Seed, of signals that there aren't any more elements:
type Counter = Int
first3NumsGreater5 :: Seed Counter Int -> Maybe (Int, Seed Counter Int)
first3NumsGreater5 (Seed {acc, pending})
| acc >= 3 =
Nothing
| otherwise =
case dropWhile (<= 5) pending of
[] -> Nothing
x : xs -> Just (x, Seed {acc = succ acc, pending = xs})
Now our main function can be written in terms of unfoldr:
unfoldFromList ::
(Seed acc input -> Maybe (output, Seed acc input)) ->
acc ->
[input] ->
[output]
unfoldFromList next acc pending = unfoldr next (Seed {acc, pending})
Putting it to work:
main :: IO ()
main = print $ unfoldFromList first3NumsGreater5 0 [0, 6, 2, 7, 9, 10, 11]
-- [6,7,9]
Normally an early termination-capable fold is foldr with the combining function which is non-strict in its second argument. But, its information flow is right-to-left (if any), while you want it left-to-right.
A possible solution is to make foldr function as a left fold, which can then be made to stop early:
foldlWhile :: Foldable t
=> (a -> Bool) -> (r -> a -> r) -> r
-> t a -> r
foldlWhile t f a xs = foldr cons (\acc -> acc) xs a
where
cons x r acc | t x = r (f acc x)
| otherwise = acc
You will need to tweak this for t to test the acc instead of x, to fit your purposes.
This function is foldlWhile from https://wiki.haskell.org/Foldl_as_foldr_alternative, re-written a little. foldl'Breaking from there might fit the bill a bit better.
foldr with the lazy reducer function can express corecursion perfectly fine just like unfoldr does.
And your code is already lazy: terminatingFold (\acc x -> Left acc) [1..] => []. That's why I'm not sure if this answer is "more clever", as you've requested.
edit: following a comment by #danidiaz, to make it properly lazy you'd have to code it as e.g.
first3above5 :: (Foldable t, Ord a, Num a)
=> t a -> [a]
first3above5 xs = foldr cons (const []) xs 0
where
cons x r i | x > 5 = if i==2 then [x]
else x : r (i+1)
| otherwise = r i
This can be generalized further by abstracting the test and the count.
Of course it's just reimplementing take 3 . filter (> 5), but shows how to do it in general with foldr.

Is using fold less efficient than standard recursion

I'm going through the Learn You a Haskell book right now and I'm curious about how this particular example works. The book first demonstrates an implementation of findKey using traditional recursion:
findKey :: (Eq k) => k -> [(k,v)] -> Maybe v
findKey key [] = Nothing
findKey key ((k,v):xs) = if key == k
then Just v
else findKey key xs
The book then follows up with a shorter implementation using foldr
findKey :: (Eq k) => k -> [(k,v)] -> Maybe v
findKey key = foldr (\(k,v) acc -> if key == k then Just v else acc) Nothing
With the standard recursion, the function should immediately return once it hits the first element with the provided key. If I understand the foldr implementation correctly, it will iterate over the entire list every time, even if it matched the first element it came across. That doesn't seem like a very efficient way to handle the problem.
Is there something I'm not getting about how the foldr implementation works? Or is there some kind of magic within Haskell that makes this implementation not quite as inefficient as I think it is?
foldr is written using standard recursion.
The recursive call to foldr is hidden inside of acc. If your code doesn't use acc, it will never be computed (because Haskell is lazy). So the foldr version is efficient and will also return early.
Here's an example demonstrating this:
Prelude> foldr (\x z -> "done") "acc" [0 ..]
"done"
This expression returns "done" immediately, even though the input list is infinitely long.
If foldr is defined as:
foldr f z (x : xs) = f x (foldr f z xs)
foldr _ z [] = z
, then evaluation goes via
f x (foldr f z xs)
where
f = \x z -> "done"
x = 0
z = "acc"
xs = ... -- unevaluated, but is [1 ..]
which is
(\x z -> "done") 0 (foldr (\x z -> "done") "acc" [1 ..])
which turns into "done" because the first function doesn't use z, so the recursive call is never needed.
If I understand the foldr implementation correctly, it will iterate over the entire list every time, even if it matched the first element it came across.
This is wrong. foldr will evaluate the list only as much as needed.
E.g.
foldr (&&) True [True, False, error "unreached code here"]
returns False since the error is never evaluated, precisely as in
(True && (False && (error "unreached code here" && True)))
Indeed, since the end of the list is never reached, we can also write
foldr (&&) (error "end") [True, False, error "unreached code here"]
and still obtain False.
Here is code which demonstrates that foldr does indeed "short-circuit" the evaluation of findKey:
import Debug.Trace
findKey :: (Eq k) => k -> [(k,v)] -> Maybe v
findKey key = foldr (\(k,v) acc -> if key == k then Just v else acc) Nothing
tr x = trace msg x
where msg = "=== at: " ++ show x
thelist = [ tr (1,'a'), tr (2,'b'), tr (3, 'c'), tr (4, 'd') ]
An example of running findKey in ghci:
*Main> findKey 2 thelist
=== at: (1,'a')
=== at: (2,'b')
Just 'b'
*Main>
Think of foldr using the following definition (using standard recursion):
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr f e [] = e
foldr f e (x:xs) = f x (foldr f e xs)
The third line shows that the second implementation for findKey will return upon finding the first match.
As a sidenote: assume you had the following definition (which does not have identical functionality) for findKey (as an exercise you might want to rewrite the definition using foldr):
findKey :: (Eq k) => k -> [(k,v)] -> [v]
findKey key [] = []
findKey key ((kHead, vHead):rest) = if (key == kHead) then vHead:(findKey key rest) else findKey key rest
Now you might think that this would iterate through the whole input list. Depending on how you invoke this function, it could be the case that it iterates through the whole list, but at the same time this can give you the first match efficiently too. Due to Haskell's lazy evaluation the following code:
head (findKey key li)
will give you the first match (assuming that there's one) with the same efficiency as your first example.
foldr f z [a,b,c,...,n] ==
a `f` (b `f` (c `f` (... (n `f` z) ...))) ==
f a (foldr f z [b,c,...,n]) ==
f a acc where acc = foldr f z [b,c,...,n]
So if your f returns before forcing acc, acc remains not forced, i.e. no part of the list argument beyond its head element a is accessed, like e.g. when you have
f a acc = ...
If, on the other hand, your f does force its second argument, e.g. if it's defined as
f a (x:xs) = ...
then the acc is forced before f starts its work, and the list will be accessed in whole before the processing begins -- in whole, because acc = f b acc2 and that invocation of f must force its second argument, acc2, so its value, acc, can be forced (pattern-matched with (x:xs), that is); and so forth.

Find the K'th element of a list using foldr

I try to implement own safe search element by index in list.
I think, that my function have to have this signature:
safe_search :: [a] -> Int -> Maybe a
safe_search xs n = foldr iteration init_val xs n
iteration = undefined
init_val = undefined
I have problem with implementation of iteration. I think, that it has to look like this:
safe_search :: [a] -> Int -> Maybe a
safe_search xs n = foldr iteration init_val xs n
where
iteration :: a -> (Int -> [a]) -> Int -> a
iteration x g 0 = []
iteration x g n = x (n - 1)
init_val :: Int -> a
init_val = const 0
But It has to many errors. My intuition about haskell is wrong.
you have
safe_search :: [a] -> Int -> Maybe a
safe_search xs n = foldr iteration init_val xs n
if null xs holds, foldr iteration init_val [] => init_val, so
init_val n
must make sense. Nothing to return, so
= Nothing
is all we can do here, to fit the return type.
So init_val is a function, :: Int -> Maybe a. By the definition of foldr, this is also what the "recursive" argument to the combining function is, "coming from the right":
iteration x r
but then this call must also return just such a function itself (again, by the definition of foldr, foldr f z [a,b,c,...,n] == f a (f b (f c (...(f n z)...))), f :: a -> b -> b i.e. it must return a value of the same type as it gets in its 2nd argument ), so
n | n==0 = Just x
That was easy, 0-th element is the one at hand, x; what if n > 0?
| n>0 = ... (n-1)
Right? Just one more step left for you to do on your own... :) It's not x (the list's element) that goes on the dots there; it must be a function. We've already received such a function, as an argument...
To see what's going on here, it might help to check the case when the input is a one-element list, first,
safe_search [x] n = foldr iteration init_val [x] n
= iteration x init_val n
and with two elements,
[x1, x2] n = iteration x1 (iteration x2 init_val) n
-- iteration x r n
Hope it is clear now.
edit: So, this resembles the usual foldr-based implementation of zip fused with the descending enumeration from n down, indeed encoding the more higher-level definition of
foo xs n = ($ zip xs [n,n-1..]) $
dropWhile ((>0) . snd) >>>
map fst >>>
take 1 >>> listToMaybe
= drop n >>> take 1 >>> listToMaybe $ xs
Think about a few things.
What type should init_val have?
What do you need to do with g? g is the trickiest part of this code. If you've ever learned about continuation-passing style, you should probably think of both init_val and g as continuations.
What does x represent? What will you need to do with it?
I wrote up an explanation some time ago about how the definition of foldl in terms of foldr works. You may find it helpful.
I suggest to use standard foldr pattern, because it is easier to read and understand the code, when you use standard functions:
foldr has the type foldr :: (a -> b -> b) -> [a] -> b -> [b],
where third argument b is the accumulator acc for elements of your list [a].
You need to stop adding elements of your list [a] to acc after you've added desired element of your list. Then you take head of the resulting list [b] and thus get desired element of the list [a].
To get n'th element of the list xs, you need to add length xs - n elements of xs to the accumulator acc, counting from the end of the list.
But where to use an iterator if we want to use the standard foldr function to improve the readability of our code? We can use it in our accumulator, representing it as a tuple (acc, iterator). We subtract 1 from the iterator each turn we add element from our initial list xs to the acc and stop to add elements of xs to the acc when our iterator is equal 0.
Then we apply head . fst to the result of our foldr function to get the desired element of the initial list xs and wrap it with Just constructor.
Of course, if length - 1 of our initial list xs is less than the index of desired element n, the result of the whole function safeSearch will be Nothing.
Here is the code of the function safeSearch:
safeSearch :: Int -> [a] -> Maybe a
safeSearch n xs
| (length xs - 1) < n = Nothing
| otherwise = return $ findElem n' xs
where findElem num =
head .
fst .
foldr (\x (acc,iterator) ->
if iterator /= 0
then (x : acc,iterator - 1)
else (acc,iterator))
([],num)
n' = length xs - n

Why does my Haskell do-notation break when I try to desugar it?

I have the following code from Problem 26 of the 99 Haskell problems:
combinations :: Int -> [a] -> [[a]]
combinations 0 _ = return []
combinations n xs = do y:xs' <- tails xs
ys <- combinations (n-1) xs'
return (y:ys)
The above code works as expected. Below is my main function and the printed results:
main = print $ combinations 2 "abcd"
-- Prints: ["ab","ac","ad","bc","bd","cd"]
As a learning exercise I tried to "desugar" the do-notation like so:
combinations :: Int -> [a] -> [[a]]
combinations 0 _ = return []
combinations n xs = tails xs >>= \(y:xs') ->
do
ys <- combinations (n-1) xs'
return (y:ys)
This compiles, but gives the following error at runtime:
PatternMatchFail: /home/.../test.hs:(46,34)-(49,37): Non-exhaustive patterns in lambda
What is going on here? How can I replace the do-notation with >>= and >>?
From the Haskell Wikibook:
... the snippet with lambdas was "broadly equivalent" to the do block. It is not an exact translation because the do notation adds special handling of pattern match failures.
Consider this example:
f xs = do
(x:_) <- Just xs
return x
g xs = Just xs >>=
\(x:_) -> return x
For any non-empty list, these functions are identical. But f [] returns Nothing, and g [] returns an error much like the one you're getting.
This is because the do notation handles failure differently. The Monad typeclass has a fail function. You're using the list monad, which fails by returning an empty list. The Maybe monad implement it by returning Nothing. Either way, the pattern match failure inside the do notation is handled with this function, hence the difference.
So the correct way to translate it would be:
g xs = Just xs >>=
\xs' -> case xs' of
(x:_) -> return x
[] -> fail "some error"

Resources