Recently I have been learning about compositions in haskell and am now a bit confused concerning this example.
(const . min) 3 0 4
As a result I get 3, so internally it must be computed like:
const (min 3) 0 4
But I thought since min takes two arguments, it should look like this:
const (min 3 0) 4
So apparently the composition only takes this one argument, in this case 3, instead of all the arguments for min like I expected it to. Does that mean compositions only take one argument per default or what am I not getting here?
You can answer your question by manually evaluating the initial expression.
(const . min) 3 0 4
⇒ (\x -> const (min x)) 3 0 4 * defn of (.)
⇒ (const (min 3)) 0 4 * function application
⇒ ((\x y -> x) (min 3)) 0 4 * defn of const
⇒ (\y -> min 3) 0 4 * function application
⇒ (min 3) 4 * function application
⇒ 3 * because 3 is less than 4
It is worth noting that function application is left-associative, so, f x y means the same as (f x) y.
It is also worth noting that \x y -> z means the same as \x -> \y -> z.
Related
I have the following two Haskell expressions:
map (\f x -> f x 5) [(-),(+),(*)]
map (\f x -> f 5 x) [(-),(+),(*)]
And I'm trying to figure out whether either expression above is equivalent to the following expression:
map ($ 5) [(-),(+),(*)]
I am trying to understand what the difference between the first two expressions is.
Since for both expressions, there is only one parameter passed to the lambda function (e.g. the operator), the function will be partially applied.
Is it correct to say that the elements in the result list from the first expression will be:
(1) - x 5 = (- x) 5
(2) + x 5 = (+ x) 5
(3) * x 5 = (* x) 5
And for the second expression:
(1) - 5 x = (- 5) x
(2) + 5 x = (+ 5) x
(3) * 5 x = (* 5) x
However, I don't think that either expression is equivalent to map ($ 5) [(-),(+),(*)]. This is because (- x) 5 (where x is a number) gives an error in GHCI and is an invalid expression. Similarly (- 5) x also gives an error.
On the other hand, map ($5) [(-)], results in a function that takes a number and subtracts it from 5.
Is this reasoning correct? Any insights are appreciated.
(- 5) 5 gives out an error because prefix minus is a special case in the language syntax: (- 5) means minus five, the number, and not a function that subtracts five (see also: Currying subtraction). That being so, I will focus on the (+) case, which is not exceptional.
In your second expression, map (\f x -> f 5 x) [(-),(+),(*)], the second element of the result list will be:
(\f x -> f 5 x) (+)
When evaluating such a thing by hand, it is important to be careful to not mix up prefix, infix and sectioned uses of operators. Application here gives out...
\x -> (+) 5 x -- Prefix syntax (note the parentheses around the operator)
... which is equivalent to...
\x -> 5 + x -- Infix syntax
... and to:
\x -> (5 +) x -- Left section
\x -> (+ x) 5 -- Right section
(5 +) -- Left section, pointfree
So the sections, which are patterned after infix usage of the operators, should be the other way around relative to your question. As for map ($ 5) [(-),(+),(*)], it is equivalent to map (\f x -> f 5 x) [(-),(+),(*)], your second expression. You can confirm that by using the fact that ($) f x = f x to figure out what the ($ 5) right section is.
First thing, I understand (almost) fold functions. Given the function I can work out easily what will happen and how to use it.
The question is about the way it is implemented which leads to slight difference in the function definition which took some time to understand.To make matters worse most example for folds have same type of the list and default case, which does not help in the understranding as these can be different.
Usage:
foldr f a xs
foldl f a xs
where a is the default case
definition:
foldr: (a -> b -> b) -> b -> [a] -> b
foldl: (a -> b -> a) -> a -> [b] -> a
In definition I understand a is the first variable to be passed and b second variable to be passed to function.
Eventually I understood that this is happening due to the fact that when f finally gets evaluated in foldr it is implemented as f x a (i.e. default case is passed as second parameter). But for foldl it is implemented as f a x (i.e. default case is passed as first parameter).
Would not the function definition be same if we had passed the default case as same (either 1st parameter in both or 2nd) in both cases? Was there any particular reason for this choice?
To make things a little clearer, I will rename a couple type variables in your foldl signature...
foldr: (a -> b -> b) -> b -> [a] -> b
foldl: (b -> a -> b) -> b -> [a] -> b
... so that in both cases a stands for the type of the list elements, and b for that of the fold results.
The key difference between foldr and foldl can be seen by expanding their recursive definitions. The applications of f in foldr associate to the right, and the initial value shows up to the right of the elements:
foldr f a [x,y,z] = x `f` (y `f` (z `f` a))
With foldl, it is the other way around: the association is to the left, and the initial value shows up to the left (as Silvio Mayolo emphasises in his answer, that's how it has to be so that the initial value is in the innermost sub-expression):
foldl f a [x,y,z] = ((a `f` x) `f` y) `f` z
That explains why the list element is the first argument to the function given to foldr, and the second to the one given to foldl. (One might, of course, give foldl the same signature of foldr and then use flip f instead of f when defining it, but that would achieve nothing but confusion.)
P.S.: Here is a good, simple example of folds with the types a and b different from each other:
foldr (:) [] -- id
foldl (flip (:)) [] -- reverse
A fold is a type of catamorphism, or a way of "tearing down" a data structure into a scalar. In our case, we "tear down" a list. Now, when working with a catamorphism, we need to have a case for each data constructor. Haskell lists have two data constructors.
[] :: [a]
(:) :: a -> [a] -> [a]
That is, [] is a constructor which takes no arguments and produces a list (the empty list). (:) is a constructor which takes two arguments and makes a list, prepending the first argument onto the second. So we need to have two cases in our fold. foldr is the direct example of a catamorphism.
foldr :: (a -> b -> b) -> b -> [a] -> b
The first function will be called if we encounter the (:) constructor. It will be passed the first element (the first argument to (:)) and the result of the recursive call (calling foldr on the second argument of (:)). The second argument, the "default case" as you call it, is for when we encounter the [] constructor, in which case we simply use the default value itself. So it ends up looking like this
foldr (+) 4 [1, 2, 3]
1 + (2 + (3 + 4))
Now, could we have designed foldl the same way? Sure. foldl isn't (exactly) a catamorphism, but it behaves like one in spirit. In foldr, the default case is the innermost value; it's only used at the "last step" of the recursion, when we've run out of list elements. In foldl, we do the same thing for consistency.
foldl (+) 4 [1, 2, 3]
((4 + 1) + 2) + 3
Let's break that down in more detail. foldl can be thought of as using an accumulator to get the answer efficiently.
foldl (+) 4 [1, 2, 3]
foldl (+) (4 + 1) [2, 3]
foldl (+) ((4 + 1) + 2) [3]
foldl (+) (((4 + 1) + 2) + 3) []
-- Here, we've run out of elements, so we use the "default" value.
((4 + 1) + 2) + 3
So I suppose the short answer to your question is that it's more consistent (and more useful), mathematically speaking, to make sure the base case is always at the innermost position in the recursive call, rather than focusing on it being on the left or the right all the time.
Consider the calls foldl (+) 0 [1,2,3,4] and foldr (+) 0 [1,2,3,4] and try to visualize what they do:
foldl (+) 0 [1,2,3,4] = ((((0 + 1) + 2) + 3) + 4)
foldr (+) 0 [1,2,3,4] = (0 + (1 + (2 + (3 + 4))))
Now, let's try to swap the arguments to the call to (+) in each step:
foldl (+) 0 [1,2,3,4] = (4 + (3 + (2 + (1 + 0))))
Note that despite the symmetry this is not the same as the previous foldr. We are still accumulating from the left of the list, I've just changed the order of operands.
In this case, because addition is commutative, we get the same result, but if you try to fold over some non-commutative function, e.g. string concatenation, the result is different. Folding over ["foo", "bar", "baz"], you would obtain "foobarbaz" or "bazbarfoo" (while a foldr would result in "foobarbaz" as well because string concatenation is associative).
In other words, the two definitions as they are make the two functions have the same result for commutative and associative binary operations (like common arithmetic addition/multiplication). Swapping the arguments to the accumulating function breaks this symmetry and forces you to use flip to recover the symmetric behavior.
The two folds yield different results due to their opposite associativity. The base value always shows up within the inner most parens. List traversal happens the same way for both folds.
right fold with (+) using the prefix notation
foldr (+) 10 [1,2,3]
=> + 1 (+ 2 (+ 3 10))
=> + 1 (+ 2 13)
=> + 1 15
=> 16
foldl (+) 10 [1,2,3]
=> + (+ (+ 10 1) 2) 3
=> + (+ 11 2) 3
=> + 13 3
=> 16
both folds evaluate to the same result because (+) is commutative, i.e.
+ a b == + b a
lets see what happens when the function is not commutative, e.g. division or exponentiation
foldl (/) 1 [1, 2, 3]
=> / (/ (/ 1 1) 2) 3
=> / (/ 1 2) 3
=> / 0.5 3
=> 0.16666667
foldr (/) 1 [1, 2, 3]
=> / 1 (/ 2 (/ 3 1))
=> / 1 (/ 2 3)
=> / 1 0.666666667
=> 1.5
now, lets evaluate foldr with function flip (/)
let f = flip (/)
foldr f 1 [1, 2, 3]
=> f 1 (f 2 (f 3 1))
=> f 1 (f 2 0.3333333)
=> f 1 0.16666667
=> 0.16666667
similarly, lets evaluate foldl with f
foldl f 1 [1, 2, 3]
=> f (f (f 1 1) 2) 3
=> f (f 1 2) 3
=> f 2 3
=> 1.5
So, in this case, flipping the order of the arguments of the folding function can make left fold return the same value as a right fold and vice versa. But that is not guaranteed. Example:
foldr (^) 1 [1, 2, 3] = 1
foldl (^) 1 [1, 2, 3] = 1
foldr (flip (^)) 1 [1,2,3] = 1
foldl (flip (^)) 1 [1,2,3] = 9 -- this is the odd case
foldl (flip (^)) 1 $ reverse [1,2,3] = 1
-- we again get 1 when we reverse this list
incidentally, reverse is equivalent to
foldl (flip (:)) []
but try defining reverse using foldr
My homework went really well until I stumpled upon the last task.
First, I had to define a custom List structure:
data List a = Nil | Cons a (List a) deriving Show
Another task was to write a custom fold function:
foldList :: (a -> b -> b) -> b -> List a -> b
foldList f b Nil = b
foldList f b (Cons a l) = f a (foldList f b l)
The second parameter is the value that is used at the end of the list (at a Nil element).
I also had to write a function prodList that multiplies every element of the provided list with each other:
prodList :: List Int -> Int
prodList = foldList (\x y -> x * y) 1
The 1 at the end is the neutral element of multplication. It therefore has no effect on the calculation.
The last one, though, is hard for me to solve.
I have to write a function binList that calculates the decimal value of list that represents a binary number. The least significant bit is the first element of the list, the binary number is therefore reversed.
A given example is that the result of binList (Cons 1 (Cons 0 (Cons 0 (Cons 0 (Cons 1 Nil))))) should be 19 (since (10001)_2 is (19)_10). The result of the list [1,1,0,1], however, should be (1011)_2=(11)_10).
The culprit of the assignment is, that we have to use foldList.
I know how to calculate each digit, but I struggle to find a way to find out which index i I'm currently at:
binList :: List Int -> Int
binList = foldList (\x y -> 2^i*x + y)
There probably is a nice, curry way to solve this in Haskell. Could you explain to me how you would solve this assignment?
If you were to write out the calculation, it would look like this:
x0 + 2 * x1 + 4 * x2 + 8 * x3 + ...
This might suggest you need to use the index, but if you factorize this expression, you get this instead:
x0 + 2 * (x1 + 2 * (x2 + 2 * (x3 ...
Do you see how it can be written as a fold now? Notice that there is a self-similarity that looks kind of like this:
x + 2 * x'
Hopefully that's enough of a hint for you :)
Is it possible in Haskell to write a function which add up all items from an integer list and if a sum in the middle of the list is under 0, than restart add up with 0. I mean something like this:
[2,5,-6,-2,8,4]
2 + 5 = 7
7 - 6 = 1
1 - 2 = -1 restart here because we are under 0
0 + 8 = 8
8 + 4 = 12
function return 12
Of course I know that I can add up all items from a list with this code:
sum :: [Int] -> Int
sum [x] = x
sum (x:l) = x + sum l
But I do not know how I can restart the function if a sum is under 0. Any ideas for that or is that not possible in an functional coding language because we don't have real variables or something else?
Let me use scanl to show what is going on and then foldl to get only the actual result.
First let us simply try to add all elements of the list:
Prelude> scanl (+) 0 [2,5,-6,-2,8,4]
[0,2,7,1,-1,7,11]
This is equivalent to:
Prelude> scanl (\a b -> a+b) 0 [2,5,-6,-2,8,4]
[0,2,7,1,-1,7,11]
To avoid negative intermediate numbers you can change it like this:
Prelude> scanl (\a b -> max 0 (a+b)) 0 [2,5,-6,-2,8,4]
[0,2,7,1,0,8,12]
To get only the actual result, replace scanl by foldl:
Prelude> foldl (\a b -> max 0 (a+b)) 0 [2,5,-6,-2,8,4]
12
It's very possible, you use an accumulator variable.
sumPos xs = go 0 xs where
go acc [] = acc
go acc (x:xs) = go (max (acc + x) 0) xs
This can be factored by built-in recursion functions like foldl' very nicely.
sumPos = foldl' step 0 where
step x acc = max 0 (x + acc)
Or even foldl' (max 0 .: (+)) 0 if you define (.:) = (.).(.) as some people like to.
I am trying to write this function which applies the function f twice on x
Prelude> applyTwice :: (a -> a) -> a -> a
Prelude> let applyTwice f x = f (f x)
Now, when I try to evaluate the below expression
Prelude> applyTwice (`subtract` 3) 10
Output: 10
Prelude> applyTwice (3 `subtract`) 10
Output: 4
As per my understanding, subtract is a infix function, so the given parameter should fill the empty position (left or right operand) and hence the first expression applyTwice (`subtract` 3) 10 should behave like
10 `subtract` 3 `subtract` 3
So, the result in this case should be 4, but the output is 10
While in the other case, i.e. applyTwice (3 `subtract`) 10, the output is 4, where I am expecting it to be 10
Am I going wrong somewhere?
Your understanding of applyTwice and of the operator section notation are correct. However, you're probably confused by what subtract does. See the library documentation which says:
the same as flip (-)
So subtract is like (-) but with the arguments flipped. Therefore,
applyTwice (`subtract` 3) 10
=
(`subtract` 3) ((`subtract` 3) 10)
=
(`subtract` 3) (10 `subtract` 3)
=
((10 `subtract` 3) `subtract` 3)
=
(3 - 10) `subtract` 3
=
(-7) `subtract` 3
=
3 - (-7)
=
10
And similarly for the other expression.