is mult_add a real function? What does it do? - haskell

I have the following question given to me.
Write a function form_number_back that takes a list of positive integers and forms a decimal number using the numbers in the list in reverse order.
For example form_number_back [1, 2, 3, 4] should return the number 4321;
form_number_back [ ] returns 0
Use the function foldr and mult_add below to accomplish this mult_add d s = d + 10*s
Note: foldr and foldr1 are two different functions. Try to use foldr1 instead of foldr in your definition and see if you get the same results with an empty list. Explain your results.
I cannot find anything on mult_add. I thought mabye it was the function name but she wants form_number_back as the function name. Which means mult_add is a Haskell function.
Can anyone explain to me what mult_add does? Is it even written right? Is mult_add another usermade function i'm supposed to use with my own code?
Edit 2
I tried putting in the function example to get its type..
so..
form_number_back [1, 2, 3, 4] :: Num b => b -> [b] -> b
so my function looks like
form_number_back a = foldr(mult_add)
but is returning type of
form_number_back :: Num b => [t] -> b -> [b] -> b
Trying to figure out how to get rid of that [t]

Types are both more important and more informative in Haskell than in most other languages. When you don't understand Haskell, a good first step is to think about types. So let's do that. We'll fire up ghci and enter:
Prelude> let mult_add d s = d + 10 * s
And now ask for its type:
Prelude> :t mult_add
mult_add :: Num a => a -> a -> a
That is, mult_add takes an a and another a, and returns an a, with the proviso that a is an instance of the Num class (so that you can add and multiply them).
You're asked to use foldr to write this function, so let's look at the type of that:
Prelude> :t foldr
foldr :: (a -> b -> b) -> b -> [a] -> b
That looks a bit intimidating, so let's break it down. The first part, (a -> b -> b) tells us that foldr needs a function of two variables, a and b. Well, we have one of those already - it's mult_add. So what happens if we feed in mult_add as the first argument to foldr?
Prelude> :t foldr mult_add
foldr mult_add :: Num b => b -> [b] -> b
Okay! We now have a function that takes a b and a [b] (a list of bs) and returns a b. The function you're trying to write needs to return 0 when it's given the empty list, so let's try feeding it the empty list, with a few different values for the remaining argument:
Prelude> foldr mult_add 10 []
10
Prelude> foldr mult_add 5 []
5
Hey, that's interesting. If we feed it the number x and the empty list, it just returns x (Note: this is always true for foldr. If we give it the initial value x and the empty list [], it will return x, no matter what function we use in place of mult_add.)
So let's try feeding it 0 as the second argument:
Prelude> foldr mult_add 0 []
0
That seems to work. Now how about if we feed it the list [1,2,3,4] instead of the empty list?
Prelude> foldr mult_add 0 [1,2,3,4]
4321
Nice! So it seems to work. Now the question is, why does it work? The trick to understanding foldr is that foldr f x xs inserts the function f between every element of xs, and additionally puts x at the end of the list, and collects everything from the right (that's why it's called a right fold). So, for example:
foldr f 0 [1,2,3] = 1 `f` (2 `f` (3 `f` 0))
where the backticks indicate that we're using the function in its infix form (so its first argument is the one on the left, and the second argument is the one on the right). In your example you have f = mult_add, which multiplies its second argument by 10 and adds it to the first argument:
d `mult_add` s = d + 10 * s
so you have
foldr mult_add 0 [1,2,3] = 1 `mult_add` (2 `mult_add` (3 `mult_add 0))
= 1 `mult_add` (2 `mult_add` 3)
= 1 `mult_add` 32
= 321
which does what you expect. To make sure you understand this, work out what would happen if you defined mult_add the other way around, i.e.
mult_add d s = 10 * d + s

Related

Haskell - counting with foldr

Working on a Haskell problem, fairly new to the language. I am trying to count the occurence of tuple values that are present in the list of tuples.
My tuples look like this: [(5, [7,2]), (2,[5,7,1,6])]
So far, using foldr, I have done this:
testFunc = foldr (\x-> const succ) 0
However, this only retrieves the count of the left side of the tuple. I am a little confused, how to solve this?
-- Expected output: 6
-- Current output: 2
The type of foldr is:
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
This means that the function it's talking should take the current value and the accumulator and will return a value of the same type as the accumulator. It then takes an initial value for the accumulator, and finally the Foldable thing to iterate over.
The accumulator is clearly the count, and for an empty list, it'll be zero, so there's our initial accumulator value.
We then just have to add the length of the list to that accumulator each time through. We can pattern match this data out. We'll use _ for the first item in each tuple, because we just don't care about that value.
Prelude> testData = [(5, [7,2]), (2,[5,7,1,6])]
Prelude> foldr (\(_, lst) count -> count + length lst) 0 testData
6
Prelude>

Haskell's foldr/foldl definitions trip newbie? For foldl Actual function takes f (default case) x while for foldr function takes f x (default case)?

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

How is this function equivalent to getting the last item in a list?

After completing the first problem ("Find the last element of a list") in the 99 questions exercises, I wanted to see how my solution compared with others and I found this solution.
myLast' = foldr1 (const id)
This documentation seems to show that foldr1 takes two arguments, the first being a function and the second being a list. But this definition only appears to take a function as an argument. Is there an implicit definition of the arguments passed like this?
myLast' xs = foldr1 (const id) xs
I have looked up the definitions of foldr1, const, and id, but I'm having a hard time understanding how those three work together to return the last item in the list.
You're exactly right. In Haskell, a function that takes two arguments can actually be treated as a function that takes one argument and returns another function that takes an argument; this is known as currying. Note that the function signature for foldr1 is:
(a -> a -> a) -> [a] -> a
While we often think of it as "a function that takes a function and a list as arguments and returns a value", it's really "a function that takes a function as an argument and returns a function that takes a list and returns a value".
As mipadi explains, the function is being curried. That explains how the list argument gets there, but perhaps doesn't explain how the actual fold works.
The const id bit is a little trixy. foldr1 is expecting to get something that has the type a -> a -> a. The definitions of these functions are
const :: x -> y -> x
const x y = x
id :: x -> x
id x = x
So, mangling that all together, we have
const id =
\ y -> id =
\ y -> \ x -> x =
\ y x -> x
In order words, const id does the same thing as flip const; it's a 2-argument function that throws the first argument away, and returns the second one. It's not terribly obvious that this is so; IMHO, flip const would be clearer.
foldr1 will call this function with the old value as the first argument, and the next list element as the second argument. This function always returns the next list element. The final output from foldr is the last output from the function, which will be the last element of the entire list.
Yes, your intuition about functions not needing all their arguments is spot on. And when one function takes another function as a parameter to return another function as a result, it is called "currying." See: http://en.wikipedia.org/wiki/Currying.
(As a side note, this was actually discovered (or rediscovered) by Haskell Curry, which is how our Haskell got its name.)
If the idea of currying is still taking time to sink in, this may help:
There are actually two functions defined in Prelude called curry and uncurry. They carry the following types:
Prelude> :t curry
curry :: ((a, b) -> c) -> a -> b -> c
Prelude> :t uncurry
uncurry :: (a -> b -> c) -> (a, b) -> c
uncurry takes a 2 argument curried function (or a function that takes a function of one argument that returns a function of one argument,) and produces an uncurrried function, or a function that takes all of the arguments all at once (as a tuple.)
curry, as you may imply by the name and by its type, goes the other way, so that it takes a curried function (a function that takes all the arguments at once) and produces a function that takes one argument and returns a function that takes the other argument.
Most programming languages work by default in a uncurried fashion, you provide all the arguments and get a result, while Haskell is curried by default.
Now for an example of uncurry, we can take a simple function, (+):
Prelude> :t (+)
(+) :: Num a => a -> a -> a
Prelude> (+) 1 2
3
Prelude> :t (+)
(+) :: Num a => a -> a -> a
Prelude> :t uncurry (+)
uncurry (+) :: Num c => (c, c) -> c
Prelude> uncurry (+) (1,2)
3
And, we could also do this with const if we want to:
Prelude> :t const
const :: a -> b -> a
Prelude> const 1 2
1
Prelude> :t uncurry const
uncurry const :: (c, b) -> c
Prelude> uncurry const (1,2)
1
But having an uncurried version of const is just not very useful, because there is no point in having a function that takes two arguments and always returns the first one if you have to specify all the arguments up front.
const is useful precisely because it is curried and can be given in a place where a function is needed that takes two arguments and simply returns the first one.
Like in foldr1, for example:
Prelude> :t foldr1
foldr1 :: (a -> a -> a) -> [a] -> a
Where the first argument is a curried function of two arguments.
And since the return value of a function can be a function, it can also be so with const:
Prelude> :t const id
const id :: b -> a -> a
const id simply takes an argument of any type b and returns the id function.
So if we can apply const id step by step:
Prelude> :t const id 1
const id 1 :: a -> a
const id 1 or const id anyOtherValueHere just returns the id function.
Which can be used liked so:
Prelude> :t const id "Giraffe" 100
const id "Giraffe" 100 :: Num a => a
Prelude> const id "Giraffe" 100
100
Prelude> :t const id (\a b -> undefined) 100
const id (\a b -> undefined) 100 :: Num a => a
Prelude> const id (\a b -> undefined) 100
100
So, const really ignores its second argument. Directly above, is just like applying id to 100.
So, foldr1 (const id) simply takes a list and keeps applying id to each set of two elements and keeping the second one (because const id returns the value of id on the second argument passed in) until we have the last element.
You are correct that your two examples can be replaced by one another. This can be thought of as algebraic cancelation just like in algebra class.
f x y = g x y
I can cancel the y on each side:
f x = g x
now I can cancel the x on each side:
f = g
Take a look a the wiki page for foldr vs foldl and foldl' to learn a little more about foldr.
To get an idea of how myLast' works we can do some algebraic suptitution.
myLast' [1, 2, 3]
== foldr1 (const id) [1, 2, 3]
Now we should use the definition of foldr1 in-particular: foldr1 f (x:xs) = f x (foldr1 f xs)
== (const id) 1 (foldr1 (const id) [2, 3])
const id turns out to have the type sig b -> a -> a which is the same as flip const and it turns out it acts the same as well which is a function that ignores its first argument and returns the second. example: (const id) 1 3 == 3 * see below for a little more *
== foldr1 (const id) [2, 3]
== foldr1 (const id) [3]
== 3
That last step may not be what you expected but if you check the definition of foldr1 it contains:
foldr1 _ [x] = x
Which pattern matches when their is only one element in the list and returns it.
* How does const id work?
const returns its first argument and ignores it second so
const id 3 == id
const id 3 4 == id 4 == 4

Composing a chain of 2-argument functions

So I have a list of a functions of two arguments of the type [a -> a -> a]
I want to write a function which will take the list and compose them into a chain of functions which takes length+1 arguments composed on the left. For example if I have [f,g,h] all of types [a -> a -> a] I need to write a function which gives:
chain [f,g,h] = \a b c d -> f ( g ( h a b ) c ) d
Also if it helps, the functions are commutative in their arguments ( i.e. f x y = f y x for all x y ).
I can do this inside of a list comprehension given that I know the the number of functions in question, it would be almost exactly like the definition. It's the stretch from a fixed number of functions to a dynamic number that has me stumped.
This is what I have so far:
f xs = f' xs
where
f' [] = id
f' (x:xs) = \z -> x (f' xs) z
I think the logic is along the right path, it just doesn't type-check.
Thanks in advance!
The comment from n.m. is correct--this can't be done in any conventional way, because the result's type depends on the length of the input list. You need a much fancier type system to make that work. You could compromise in Haskell by using a list that encodes its length in the type, but that's painful and awkward.
Instead, since your arguments are all of the same type, you'd be much better served by creating a function that takes a list of values instead of multiple arguments. So the type you want is something like this: chain :: [a -> a -> a] -> [a] -> a
There are several ways to write such a function. Conceptually you want to start from the front of the argument list and the end of the function list, then apply the first function to the first argument to get something of type a -> a. From there, apply that function to the next argument, then apply the next function to the result, removing one element from each list and giving you a new function of type a -> a.
You'll need to handle the case where the list lengths don't match up correctly, as well. There's no way around that, other than the aforementioned type-encoded-lengths and the hassle associate with such.
I wonder, whether your "have a list of a functions" requirement is a real requirement or a workaround? I was faced with the same problem, but in my case set of functions was small and known at compile time. To be more precise, my task was to zip 4 lists with xor. And all I wanted is a compact notation to compose 3 binary functions. What I used is a small helper:
-- Binary Function Chain
bfc :: (c -> d) -> (a -> b -> c) -> a -> b -> d
bfc f g = \a b -> f (g a b)
For example:
ghci> ((+) `bfc` (*)) 5 3 2 -- (5 * 3) + 2
17
ghci> ((+) `bfc` (*) `bfc` (-)) 5 3 2 1 -- ((5 - 3) * 2) + 1
5
ghci> zipWith3 ((+) `bfc` (+)) [1,2] [3,4] [5,6]
[9,12]
ghci> getZipList $ (xor `bfc` xor `bfc` xor) <$> ZipList [1,2] <*> ZipList [3,4] <*> ZipList [5,6] <*> ZipList [7,8]
[0,8]
That doesn't answers the original question as it is, but hope still can be helpful since it covers pretty much what question subject line is about.

How does currying work?

I'm very new to Haskell and FP in general. I've read many of the writings that describe what currying is, but I haven't found an explanation to how it actually works.
Here is a function: (+) :: a -> (a -> a)
If I do (+) 4 7, the function takes 4 and returns a function that takes 7 and returns 11. But what happens to 4 ? What does that first function do with 4? What does (a -> a) do with 7?
Things get more confusing when I think about a more complicated function:
max' :: Int -> (Int -> Int)
max' m n | m > n = m
| otherwise = n
what does (Int -> Int) compare its parameter to? It only takes one parameter, but it needs two to do m > n.
Understanding higher-order functions
Haskell, as a functional language, supports higher-order functions (HOFs). In mathematics HOFs are called functionals, but you don't need any mathematics to understand them. In usual imperative programming, like in Java, functions can accept values, like integers and strings, do something with them, and return back a value of some other type.
But what if functions themselves were no different from values, and you could accept a function as an argument or return it from another function? f a b c = a + b - c is a boring function, it sums a and b and then substracts c. But the function could be more interesting, if we could generalize it, what if we'd want sometimes to sum a and b, but sometimes multiply? Or divide by c instead of subtracting?
Remember, (+) is just a function of 2 numbers that returns a number, there's nothing special about it, so any function of 2 numbers that returns a number could be in place of it. Writing g a b c = a * b - c, h a b c = a + b / c and so on just doesn't cut it for us, we need a general solution, we are programmers after all! Here how it is done in Haskell:
let f g h a b c = a `g` b `h` c in f (*) (/) 2 3 4 -- returns 1.5
And you can return functions too. Below we create a function that accepts a function and an argument and returns another function, which accepts a parameter and returns a result.
let g f n = (\m -> m `f` n); f = g (+) 2 in f 10 -- returns 12
A (\m -> m `f` n) construct is an anonymous function of 1 argument m that applies f to that m and n. Basically, when we call g (+) 2 we create a function of one argument, that just adds 2 to whatever it receives. So let f = g (+) 2 in f 10 equals 12 and let f = g (*) 5 in f 5 equals 25.
(See also my explanation of HOFs using Scheme as an example.)
Understanding currying
Currying is a technique that transforms a function of several arguments to a function of 1 argument that returns a function of 1 argument that returns a function of 1 argument... until it returns a value. It's easier than it sounds, for example we have a function of 2 arguments, like (+).
Now imagine that you could give only 1 argument to it, and it would return a function? You could use this function later to add this 1st argument, now encased in this new function, to something else. E.g.:
f n = (\m -> n - m)
g = f 10
g 8 -- would return 2
g 4 -- would return 6
Guess what, Haskell curries all functions by default. Technically speaking, there are no functions of multiple arguments in Haskell, only functions of one argument, some of which may return new functions of one argument.
It's evident from the types. Write :t (++) in interpreter, where (++) is a function that concatenates 2 strings together, it will return (++) :: [a] -> [a] -> [a]. The type is not [a],[a] -> [a], but [a] -> [a] -> [a], meaning that (++) accepts one list and returns a function of type [a] -> [a]. This new function can accept yet another list, and it will finally return a new list of type [a].
That's why function application syntax in Haskell has no parentheses and commas, compare Haskell's f a b c with Python's or Java's f(a, b, c). It's not some weird aesthetic decision, in Haskell function application goes from left to right, so f a b c is actually (((f a) b) c), which makes complete sense, once you know that f is curried by default.
In types, however, the association is from right to left, so [a] -> [a] -> [a] is equivalent to [a] -> ([a] -> [a]). They are the same thing in Haskell, Haskell treats them exactly the same. Which makes sense, because when you apply only one argument, you get back a function of type [a] -> [a].
On the other hand, check the type of map: (a -> b) -> [a] -> [b], it receives a function as its first argument, and that's why it has parentheses.
To really hammer down the concept of currying, try to find the types of the following expressions in the interpreter:
(+)
(+) 2
(+) 2 3
map
map (\x -> head x)
map (\x -> head x) ["conscience", "do", "cost"]
map head
map head ["conscience", "do", "cost"]
Partial application and sections
Now that you understand HOFs and currying, Haskell gives you some syntax to make code shorter. When you call a function with 1 or multiple arguments to get back a function that still accepts arguments, it's called partial application.
You understand already that instead of creating anonymous functions you can just partially apply a function, so instead of writing (\x -> replicate 3 x) you can just write (replicate 3). But what if you want to have a divide (/) operator instead of replicate? For infix functions Haskell allows you to partially apply it using either of arguments.
This is called sections: (2/) is equivalent to (\x -> 2 / x) and (/2) is equivalent to (\x -> x / 2). With backticks you can take a section of any binary function: (2`elem`) is equivalent to (\xs -> 2 `elem` xs).
But remember, any function is curried by default in Haskell and therefore always accepts one argument, so sections can be actually used with any function: let (+^) be some weird function that sums 4 arguments, then let (+^) a b c d = a + b + c in (2+^) 3 4 5 returns 14.
Compositions
Other handy tools to write concise and flexible code are composition and application operator. Composition operator (.) chains functions together. Application operator ($) just applies function on the left side to the argument on the right side, so f $ x is equivalent to f x. However ($) has the lowest precedence of all operators, so we can use it to get rid of parentheses: f (g x y) is equivalent to f $ g x y.
It is also helpful when we need to apply multiple functions to the same argument: map ($2) [(2+), (10-), (20/)] would yield [4,8,10]. (f . g . h) (x + y + z), f (g (h (x + y + z))), f $ g $ h $ x + y + z and f . g . h $ x + y + z are equivalent, but (.) and ($) are different things, so read Haskell: difference between . (dot) and $ (dollar sign) and parts from Learn You a Haskell to understand the difference.
You can think of it like that the function stores the argument and returns a new function that just demands the other argument(s). The new function already knows the first argument, as it is stored together with the function. This is handled internally by the compiler. If you want to know how this works exactly, you may be interested in this page although it may be a bit complicated if you are new to Haskell.
If a function call is fully saturated (so all arguments are passed at the same time), most compilers use an ordinary calling scheme, like in C.
Does this help?
max' = \m -> \n -> if (m > n)
then m
else n
Written as lambdas. max' is a value of a lambda that itself returns a lambda given some m, which returns the value.
Hence max' 4 is
max' 4 = \n -> if (4 > n)
then 4
else n
Something that may help is to think about how you could implement curry as a higher order function if Haskell didn't have built in support for it. Here is a Haskell implementation that works for a function on two arguments.
curry :: (a -> b -> c) -> a -> (b -> c)
curry f a = \b -> f a b
Now you can pass curry a function on two arguments and the first argument and it will return a function on one argument (this is an example of a closure.)
In ghci:
Prelude> let curry f a = \b -> f a b
Prelude> let g = curry (+) 5
Prelude> g 10
15
Prelude> g 15
20
Prelude>
Fortunately we don't have to do this in Haskell (you do in Lisp if you want currying) because support is built into the language.
If you come from C-like languages, their syntax might help you to understand it. For example in PHP the add function could be implemented as such:
function add($a) {
return function($b) use($a) {
return $a + $b;
};
}
Haskell is based on Lambda calculus. Internally what happens is that everything gets converted into a function. So your compiler evaluates (+) as follows
(+) :: Num a => a -> a -> a
(+) x y = \x -> (\y -> x + y)
That is, (+) :: a -> a -> a is essentially the same as (+) :: a -> (a -> a). Hope this helps.

Resources