How to express a foldl-based code with foldr? - haskell

I am attempting to convert a list of integers into a single integer using the foldr function. I have seen implementations that use the foldl function but am trying to figure out how to do the same thing using foldr.
The output should look something like:
list2int [0,1,2,3,0,4,5]
>123045
My code:
list2int :: [Int] -> Int
list2int = foldr (\x acc -> acc*10 + x) 0
However, when I run the code above using the same input, it returns 5403210. .

I don't really recommend this, but it exists.
ghci> foldr (\x k acc -> k $! (10 * acc + x)) id [0,1,2,3,0,4,5] 0
123045
The reason I don't recommend it is that it's roughly the same thing as inlining the definition of foldl', but harder to read.
And this is really a problem that should use foldl' to solve. It associates the operation the correct direction and has the correct strictness. Problems like this are the whole reason it exists.

Let's run through what happens with your function when you fold over [0, 1, 2, 3, 4, 0, 5]:
foldr (\x acc -> acc*10 + x) 0 [0, 1, 2, 3, 4, 0, 5]
foldr (\x acc -> acc*10 + x) 5 [0, 1, 2, 3, 4, 0]
foldr (\x acc -> acc*10 + x) 50 [0, 1, 2, 3, 4]
foldr (\x acc -> acc*10 + x) 504 [0, 1, 2, 3]
foldr (\x acc -> acc*10 + x) 5043 [0, 1, 2]
foldr (\x acc -> acc*10 + x) 50432 [0, 1]
foldr (\x acc -> acc*10 + x) 504321 [0]
foldr (\x acc -> acc*10 + x) 5043210 []
5043210
But what if we provide foldr with a tuple, containing our accumulator, and a base to multiply each digit by?
Our initial value will be a base of 1 and an accumulator of 0: (1, 0). Each time through, we'll multiply the base by 10.
Prelude> foldr (\x (base, acc) -> (base * 10, acc + x * base)) (1, 0) [0, 1, 2, 3, 0, 4, 5]
(10000000,123045)
Prelude>
Now, consider what happens:
foldr (\x (base, acc) -> (base * 10, acc + x * base)) (1, 0) [0, 1, 2, 3, 0, 4, 5]
foldr (\x (base, acc) -> (base * 10, acc + x * base)) (10, 5) [0, 1, 2, 3, 0, 4]
foldr (\x (base, acc) -> (base * 10, acc + x * base)) (100, 45) [0, 1, 2, 3, 0]
foldr (\x (base, acc) -> (base * 10, acc + x * base)) (1000, 45) [0, 1, 2, 3]
foldr (\x (base, acc) -> (base * 10, acc + x * base)) (10000, 3045) [0, 1, 2]
foldr (\x (base, acc) -> (base * 10, acc + x * base)) (100000, 23045) [0, 1]
foldr (\x (base, acc) -> (base * 10, acc + x * base)) (1000000, 123045) [0]
foldr (\x (base, acc) -> (base * 10, acc + x * base)) (10000000, 123045) []
(10000000, 123045)
This basic pattern of using a tuple to pass state through iterations of a fold may be useful to you in the future.
Now we just need to extract the second number in this tuple, and you have the desired result.
It's also possible to pass the base, and multiply the current number by 10 raised to that base, starting with a base power of 0.
Prelude> foldr (\x (basePow, acc) -> (basePow + 1, acc + x * 10 ** basePow)) (0, 0) [0, 1, 2, 3, 0, 4, 5]
(7.0,123045.0)
Prelude>
Credit to Will Ness for pointing out the most elegant solution to this problem with foldl. The above demonstration of foldr is just one approach to solving this problem. Hopefully viewing multiple approaches to solving the same problem will be instructive.

Using your code with [0, 1, 2, 3, 4, 0, 5] works as
foldr (\x acc -> acc*10 + x) 0 [0, 1, 2, 3, 4, 0, 5]
= {- it's easier to see this way: -}
foldr (\x acc -> x + 10*acc) 0 [0, 1, 2, 3, 4, 0, 5]
=
0 + 10*(1 + 10*(2 + 10*(3 + 10*(4 + 10*(0 + 10*(5 + 10*(0)))))))
We just replace each , (and the ending bracket) in the list with + 10*(, put the 0 in the end, and balance the parens. That is what foldr is doing.
So this treats the lists as starting with the least significant digit, instead of the most significant, as they actually are.
The correct way to express this is with the left fold,
foldl (\acc x -> acc*10 + x) 0 [0, 1, 2, 3, 4, 0, 5]
=
(((((((0)*10 + 0)*10 + 1)*10 + 2)*10 + 3)*10 + 4)*10 + 0)*10 + 5
Again, we just replace each , (and the opening bracket) in the list with )*10 + , put the 0 in the front, and balance the parens. And that's what foldl is doing.
For reasons of efficiency, as mentioned in the answer by Carl, foldl' should be used here instead of foldl (which is usually the case).
To still be doing this with foldr, it must be composed with reverse:
foldr (\x acc -> acc*10 + x) 0 . reverse $ [0, 1, 2, 3, 4, 0, 5]
and when you write out reverse as a right fold and compose the two folds into one you'll probably end up with the version shown in Carl's answer. Could be a nice exercise to work through.

Related

Why the haskell map does not work with (-1)? [duplicate]

This question already has answers here:
What is the equivalent to (+1) for the subtraction, since (-1) is seen as a negative number? [duplicate]
(3 answers)
Closed 1 year ago.
What was wrong with the following code?
map (+1) [1, 2, 3 ] == map (\x -> x + 1) [1, 2, 3]
map (1+) [1, 2, 3] == map (\x -> 1 + x) [1, 2, 3]
map (-1) [1, 2, 3] == map (\x -> x - 1) [1, 2, 3]
map (1-) [1, 2, 3] == map (\x -> 1 - x) [1, 2, 3]
Why the following does not work?
map (-1) [1, 2, 3]
(-1) is interpreted as a number: minus one. You can use subtract :: Num a => a -> a -> a to subtract a value:
map (subtract 1) [1, 2, 3] == map (\x -> x - 1) [1, 2, 3]

Can someone please explain the following code? to retrieve the diagonal of a matrix using haskell?

mainDiag :: [[a]] -> [a]
mainDiag x = zipWith (!!) x [0..]
Can someone please explain this code (particularly zipWith (!!)) and how it returns the diagonal of the matrix?
Using informal notation, you can visualize zipWith as this:
zipWith f [x0,x1,x2,...] [y0,y1,y2,...] = [f x0 y0, f x1 y1, f x2 y2, ...]
In your case, zipWith (!!) x [0..] we have
x = [x0,x1,x2,...]
[0,1,2,...] = [y0,y1,y2] (that is yn=n for all natural n)
(!!) = f
Hence, the result is
[(!!) x0 0, (!!) x1 1, (!!) x2 2, ...]
which is also written as
[x0 !! 0, x1 !! 1, x2 !! 2, ...]
This list contains the element in position 0 from the list x0, the one in position 1 from list x1, and so on. This is, therefore, the diagonal of the original list-of-lists x.
zipWith takes a two parameter function and two list. Returns the list of the results of applying the function to each pair of arguments comming from each list. Example:
zipWith (+) [1,2,3] [4,5,6] = [5,7,9] -- [1 + 4, 2 + 5, 3 + 6]
Using your example
mainDiag :: [[a]] -> [a]
mainDiag x = zipWith (!!) x [0..]
mainDiag [[1,2,3],[4,5,6], [7,8,9]] = [[1,2,3] !! 0, [4,5,6] !! 1, [7,8,9] !! 2] -- expanding the expresion
= [1, 5, 9]

Rewrite a monad computation in prefix notation

I'm trying to figure out how to rewrite a monadic computation with prefix notation (not for real practical goals, just for research), but the problem that one lambda doesn't see another one's parameter
so given a working example
*Main> [1, 3, 4] >>= \x -> [x + 1, x - 1] >>= \y -> return (y*x)
[2,0,12,6,20,12]
the rewritten one shows the error on not seeing the parameter of other lambda
*Main> (>>=) ( (>>=) [1, 3, 4] (\x -> [x + 1, x - 1]) ) (\y -> return (y*x))
<interactive>:133:68: Not in scope: `x'
but if I make the last one not using it (by replacing x with y), the computation starts working
*Main> (>>=) ( (>>=) [1, 3, 4] (\x -> [x + 1, x - 1]) ) (\y -> return (y*y))
[4,0,16,4,25,9]
So does full rewriting in prefix notation technically possible? Or this property of accessing other lambdas parameters is exclusive to the infix notation?
The problem is that you got the precedences slightly wrong, see also Haskell Precedence: Lambda and operator
The body of a lambda-expression extends as far to the right as possible. Then your example is parenthesized as follows:
[1, 3, 4] >>= (\x -> [x + 1, x - 1] >>= (\y -> return (y*x)))
Bringing it into prefix form results in
(>>=) [1, 3, 4] (\x -> (>>=) [x + 1, x - 1] (\y -> return (y*x)))
Now x is visible inside the body of \y -> ....

Understanding the functions elem and isInfixOf

A while ago I've asked a question about the function elem here, but I don't think the answer is fully satisfactory. My question is about the expression:
any (`elem` [1, 2]) [1, 2, 3]
We know elem is in a backtick so elem is an infix and my explanation is:
1 `elem` [1, 2] -- True
2 `elem` [1, 2] -- True
3 `elem` [1, 2] -- False
Finally it will return True since it's any rather than all. This looked good until I see a similar expression for isInfixOf:
any (isInfixOf [1, 2, 3]) [[1, 2, 3, 4], [1, 2]]
In this case a plausible explanation seems to be:
isInfixOf [1, 2, 3] [1, 2, 3, 4] -- True
isInfixOf [1, 2, 3] [1, 2] -- False
I wonder why they've been used in such different ways since
any (elem [1, 2]) [1, 2, 3]
will give an error and so will
any (`isInfixOf` [[1, 2, 3, 4], [1, 2]]) [1, 2, 3]
Your problem is with the (** a) syntactic sugar. The thing is that (elem b) is just the partial application of elem, that is:
(elem b) == (\xs -> elem b xs)
However when we use back ticks to make elem infix, we get a special syntax for infix operators which works like this:
(+ a) == (\ b -> b + a)
(a +) == (\ b -> a + b)
So therefore,
(`elem` xs) == (\a -> a `elem` xs) == (\ a -> elem a xs)
while
(elem xs) == (\a -> elem xs a)
So in the latter case your arguments are in the wrong order, and that is what is happening in your code.
Note that the (** a) syntactic sugar works for all infix operators except - since it is also a prefix operator. This exception from the rule is discussed here and here.
Using back-ticks around a function name turns it into an infix operator. So
x `fun` y
is the same as
fun x y
Haskell also has operator sections, f.e. (+ 1) means \x -> x + 1.
So
(`elem` xs)
is the same as
\x -> x `elem` xs
or
\x -> elem x xs
or
flip elem xs
It's called partial application.
isInfixOf [1, 2, 3] returns a function that expects one parameter.
any (elem [1, 2]) [1, 2, 3] is an error because you're looking for an element [1, 2], and the list only contains numbers, so haskell cannot match the types.

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