I'm trying to understand the concept of currying and went to the Haskell documentation. However, it says that
f is the curried form of g
Yet f takes two arguments and g only one. Since currying is converting a function which takes multiple arguments to a function which takes one argument and returns another function, shouldn't 'g' be the curried function?
From the haskell documentation
Currying is the process of transforming a function that takes multiple arguments into a function that takes just a single argument and returns another function if any arguments are still needed.
f :: a -> b -> c
is the curried form of
g :: (a, b) -> c
So this does seem contradictory to me and I also don't see any of these 2 functions return a function either.
Yet f takes two arguments and g only one.
No, in fact both functions take one parameter. In fact in Haskell all functions take exactly one parameter.
If you write a signature like:
f :: a -> b -> c
then this is a less verbose form of:
f :: a -> (b -> c)
How does that work? f is a function that takes one parameter, and then returns another function that again takes a parameter.
So take for example a function add :: Int -> Int -> Int.
If we write add 5 2, we thus calculate 5 + 2. It looks like it takes two parameters, but in fact we have written (add 5) 2. We thus call the add function with 5 as parameter. This returns a function (let us call this function add5 :: Int -> Int). So this add5 function adds 5 to a number. So if we then call add5 2, then we obtain 7, since add5 returns 5 added to the parameter.
We can however construct a function (like g) that takes one parameter that is a 2-tuple, so we can use another type to pass two values as one parameter. In fact you can see g(5, 2) is actually g (5, 2): you call the function with one parameter, a 2-tuple (5, 2).
So the currying aims to transform such g function that takes one parameter (a 2-tuple) into a function f that takes again one parameter, and this will then construct a function that will take the second element of the original 2-tuple.
The type a -> b -> c is actually a -> (b -> c).
So f doesn't take two arguments, of type a and a b and return c, it takes one argument of type a, and returns b -> c, a function from b to c.
Related
A professor teaching a class I am attending claimed the following.
A higher-order function could have only one arrow when checking its type.
I don't agree with this statement I tried to prove it is wrong. I tried to set up some function but then I found that my functions probably aren't higher-order functions. Here is what I have:
f x y z = x + y + z
f :: a -> a-> a -> a
g = f 3
g :: a -> a -> a
h = g 5
h :: a -> a
At the end of the day, I think my proof was wrong, but I am still not convinced that higher-order functions can only have more than one arrow when checking the type.
So, is there any resource or perhaps someone could prove that higher-order function may have only one arrow?
Strictly speaking, the statement is correct. This is because the usual definition of the term "higher-order function", taken here from Wikipedia, is a function that does one or both of the following:
takes a function as an argument, or
returns a function as its result
It is clear then that no function with a single arrow in its type signature can be a higher-order function, because in a signature a -> b, there is no "room" to create something of the form x -> y on either side of an arrow - there simply aren't enough arrows.
(This argument actually has a significant flaw, which you may have spotted, and which I'll address below. But it's probably true "in spirit" for what your professor meant.)
The converse is also, strictly speaking, true in Haskell - although not in most other languages. The distinguishing feature of Haskell here is that functions are curried. For example, a function like (+), whose signature is:
a -> a -> a
(with a Num a constraint that I'll ignore because it could just confuse the issue if we're supposed to be counting "arrows"), is usually thought of as being a function of two arguments: it takes 2 as and produces another a. In most languages, which all of course have an analagous function/operator, this would never be described as a higher-order function. But in Haskell, because functions are curried, the above signature is really just a shorthand for the parenthesised version:
a -> (a -> a)
which clearly is a higher-order function. It takes an a and produces a function of type a -> a. (Recall, from above, that returning a function is one of the things that characterises a HOF.) In Haskell, as I said, these two signatures are one and the same thing. (+) really is a higher-order function - we just often don't notice that because we intend to feed it two arguments, by which we really mean to feed it one argument, result in a function, then feed that function the second argument. Thanks to Haskell's convenient, parenthesis-free, syntax for applying functions to arguments, there isn't really any distinction. (This again contrasts from non-functional languages: the addition "function" there always takes exactly 2 arguments, and only giving it one will usually be an error. If the language has first-class functions, you can indeed define the curried form, for example this in Python:
def curried_add(x):
return lambda y: x + y
but this is clearly a different function from the straightforward function of two arguments that you would normally use, and usually less convenient to apply because you need to call it as curried_add(x)(y) rather than just say add(x,y).
So, if we take currying into account, the statement of your professor is strictly true.
Well, with the following exception, which I alluded to above. I've been assuming that something with a signature of the form
a -> b
is not a HOF*. That of course doesn't apply if a or b is a function. Often, that function's type will include an arrow, and we're tacitly assuming here that neither a or b contains arrows. Well, Haskell has type synonyms, so we could easily define, say:
type MyFunctionType = Int -> Int
and then a function with signature MyFunctionType -> a or a -> MyFunctionType is most certainly a HOF, even though it doesn't "look like one" from just a glance at the signature.
*To be clear here,a and b refer to specific types which are as yet unspecified - I am not referring to an actual signature a -> b which would mean a polymorphic function that applies to any types a and b, which would not necessarily be functions.
Your functions are higher order. Indeed, take for example your function:
f :: a -> a -> a -> a
f x y z = x + y + z
This is a less verbose form of:
f :: a -> (a -> (a -> a))
So it is a function that takes an a and returns a function. A higher order function is a function that (a) takes a function as parameter, or (b) returns a function. Both can be true at the same time. Here your function f returns a function.
A function thus always has type a -> b with a the input type, and b the return type. In case a has an arrow (like (c -> d) -> b), then it is a higher order function, since it takes a function as parameter.
If b has an arrow, like a -> (c -> d), then this is a higher order function as well, since it returns a function.
Yes, as Haskell functions are curried always, I can come up with minimal examples of higher order functions and examples:
1) Functions that takes a function at least as parameter, such as:
apply :: (a -> b) -> a -> b
apply f x = f x
2) at least 3 arguments:
sum3 :: Int -> Int -> Int
sum3 a b c = a + b + c
so that can be read as:
sum3 :: Int -> (Int -> Int)
why doesn't Haskell use some kind of special format to reflect this, or -> c can be understood in another way?
You can look at babel’s type signature in two ways.
(1) babel takes two inputs of type a and b; it produces an output of type c.
(2) babel takes an input of type a and produces an output of type (b -> c).
(1) gives you back a value of type c with babel fully applied. (2) gives you back a intermediate function of type (b -> c) with babel partially applied; if you choose to apply the intermediate function to a value of type b, you then get the result as you would get from case (1).
This ability to choose partially or fully apply a function gives you the power to build complex functions by gluing simple (intermediate) functions together.
why doesn't Haskell use some kind of special format to reflect this…?
By default, all functions in Haskell take one input; a function of two arguments is just a function that returns a function. Currying by default is already clear in the type signature. This is why (->) associates to the right so we don't have to write babel :: a -> (b -> c)
Haskell uses a concept called currying, which means there are only single parameter functions, and multiple parameter functions are just functions returning another functions, with the previous parameter "baked in", until all the parameters are filled in.
so
add :: Int -> Int -> Int
add x y = x + y
is equivalent to
add :: Int -> (Int -> Int)
add = \x -> \y -> x + y
You can think of a function like babel :: a -> b -> c as a pipeline.
It's a function that takes an a, then returns a function that takes a b, which then returns a c. Partial application is what makes this work, any application returns something, either a function or the last value c.
Prelude> :t (+)
(+) :: (Num a) => a -> a -> a
My lecture slide says that
a -> a -> a
means a function take two parameters and return one, and all of them are the same type. Which two are the parameters and which one is the return value?
Thank you.
There are some levels you have to master here:
level 0
a -> b -> c
is a function taking one a and one b and producing one c
level 1
well there is more to it:
a -> b -> c
which is really
a -> (b -> c)
is a function taking one a and producing another function, that takes a b and produces a c
level 2
f :: (Num a) => a -> a -> a
Adds a constraint to a (here Num - this means that a should be a number - a is an instance of the Num type-class)
So you get a function that takes an a and produces a function that takes another a and returns a a, and a needs to be an instance of Num
so every input to f has to be of the same type of number:
f 1 2 is ok
f 'a' 'b' is not ok
f (1::Int) (2::Int) is ok
f (1::Float) (2::Float) is ok
f (1::Int) (2::Float) is not ok
level 3 (understanding (+))
The last thing you have to understand here is that, (+) is defined as a part of Num so there are different + based on the used types ... and the same is true for the number literals like 0, 1, ... thats why 0 can be a Float or a Int or whatever type that is a instance of Num
The first two are parameters, the last one is the return value.
In fact, due to currying, it can be read like this: the + function (which only accepts numeric values) takes a parameter a and returns a function that takes a parameter of the same type and returns the result of the same type.
Here's a contrived example:
let addTwo = (+) 2 -- the + function takes one argument and returns a function
addTwo 3 -- we can add the second argument here and obtain 5 as returned value
Suppose we have a type like this:
a -> b -> c -> d -> e
The last thing in the sequence is the return type. So this function returns something of type e. Everything else is the argument types. So this function takes 4 arguments, who's types are a, b, c and d.
Lower-case letters denote "type variables" — variables which can stand for any type. (It doesn't have to be a single letter, but it often is.) Anything beginning with an upper-case letter is a specific type, not a variable. (For example, Int is a type, int is a type variable.)
The Num a part means that a stands for any type, but that type must implement the Num type-class. Other common contexts are Eq (defines the == operator), Ord (defines <, >, and so forth) and Show (defines the show function that converts stuff into a string).
In Haskell all functions are originally curried, right?
So, let's look at the max function, and I'll write what I understand about how this works.
When I write something like this:
max 4 5
What happens is that a new funcion is created that internally has value of 4, which then recieves a value, so this function is applied to 5 and a correct value is returned?
Did I say something wrong somehow or is this correct?
That's correct. You can remember what currying is all about by memorizing two of its most important identities:
-- Function type right-associativity:
a -> b -> c = a -> (b -> c)
-- Function application left-associativity:
f x y = (f x) y
These two identities work together and produce a curried language.
Is the result of a curried function a partially applied function? I understand how currying works and I though I understood how partial function application works, but I am unclear whether there is some cross over in the concepts.
My confusion has arisen from the following quote from Learn you a Haskell for great good, which conflicts with my previous understanding of the concept based on this blog post by John Skeet.
Simply speaking, if we call a function with too few parameters, we get
back a partially applied function, meaning a function that takes as
many parameters as we left out.
To give an example (in F# although the question is about functional programming in general)
> let add a b = a + b;;
val add : int -> int -> int
> let inc = add 1;;
val inc : (int -> int)
In this example is inc a partially applied function?
Generally speaking, currying means transforming a two-argument function into one that takes one argument and returns another one-argument function, so that the result of calling the curried function with the first argument and then the result of this with the second argument is equivalent to calling the original (uncurried) function with both arguments. In a pseudo-C language with closures and dynamic typing (or type inference), this would look something like so:
// The original, uncurried function:
function f(a, b) { return 2 * a - b; }
// The curried function:
function g(a) {
return function(b) {
return f(a, b);
}
}
// Now we can either call f directly:
printf("%i\n", f(23, 42));
// Or we can call the curried function g with one parameter, and then call the result
// with another:
printf("%i\n", (g(23))(42));
By currying multiple times, we can reduce any multi-argument function to a nested set of one-argument functions.
In Haskell, all functions are single-argument; a construct like f a b c is actually equivalent to ((f(a))(b))(c) in our fictional C-with-closures. The only way to really pass multiple arguments into a function is through tuples, e.g. f (a, b, c) - but since the syntax for curried functions is simpler, and the semantics are more flexibly, this option is seldom used.
The Haskell Prelude defines two functions, curry and uncurry to transform between these two representations: curry is of type ((a,b) -> c) -> a -> b -> c, that is, it takes a one-argument function that takes a tuple (a, b) and returns a c, and turns it into a function of type a -> b -> c, that is a function that takes an a and returns a function that takes a b and returns a c. uncurry does the reverse.
Partial application isn't really a thing; it's just a name given to the situation where you have a curried function (e.g. f a b), and instead of fully unrolling the whole chain (e.g., f 23 42), you stop somewhere along the way, and pass the resulting function further, e.g. let g = f 23. In order to partially-apply a function, it must be curried (you cannot partially apply f (a, b) as let g = f (a)), but since writing functions in a curried way is the default in Haskell, partial application is easy and common practice.
Short answer: inc is a function obtained through partial application.
The result of a curried function is a value of some type in the target language (Haskell, F# or whatever), so it MAY be a function (but it may be also an integer, a boolean, ..., depending on your declaration).
About partial application... it's just a name given to function applications that return other functions, but technically it's a function application like every other. It's not even mandatory that the function you return is based on the previous arguments. Take \x -> id for example: you always get the identity function, independently with respect to the input x.