Reputation: 737
I'm currently reading "programming in haskell" by Graham Hutton and just reached currying and function composition.In the exercise portion, there is the task to implement the curry function from scratch which is already present in the prelude module.
Here's my implementation but it's not working.Can anybody explain(I'm new to functional programming) why it's not working
my_curry :: ((a ,b) -> c) -> (a -> b -> c)
my_curry origFunc = origFunc.combine
where
combine e f = (e, f)
here's the error [added]
[1 of 1] Compiling Main ( higher_order.hs, interpreted )
higher_order.hs:92:30:
Couldn't match type `t0 -> (a, t0)' with `(a, b)'
Expected type: a -> (a, b)
Actual type: a -> t0 -> (a, t0)
In the second argument of `(.)', namely `combine'
In the expression: origFunc . combine
In an equation for `my_curry':
my_curry origFunc
= origFunc . combine
where
combine e f = (e, f)
Upvotes: 2
Views: 3040
Reputation: 7776
jozefg's answer explained why your code doesn't work, and I thought I'd contribute a fairly straightforward implementation for you to see.
Notice the function signature for my_curry
is ((a, b) -> c) -> (a -> b -> c)
. It takes in a function, and it returns a function as the result. We can capture the notion of "returning a function" easily with a lambda expression:
my_curry func = \x y -> func (x, y)
All this code does is takes in a single function on the left side of the equals sign, and returns a new function on the right hand side. The function it returns takes in its arguments one at a time, tuples them up and fires them off to whatever function we passed in.
Another way we can look at this is by removing the brackets in the type signature. Since the arrow in a type signature is right-associative, the type of my_curry
can also be written as ((a, b) -> c) -> a -> b -> c
. In this form, we can see that we can also implement my_curry
as a function taking three arguments: the input function, and an x and a y to tuple-up and send through that function. Therefore another valid way to write the function is
my_curry func x y = func (x, y)
Upvotes: 5
Reputation: 53911
The issue is that .
is meant to take to single argument functions and glue them together,
In this case combine
has the type a -> b -> (a, b)
. So it's first argument is a
and it's return type is b -> (a, b)
(remember that ->
groups to the right). So .
has the type
(.) :: (b -> c) -> (a -> b) -> a -> c
Since combine
is the second argument haskell is going to unify .
s type variables like
(.).a ~ combine.a
(.).b ~ (combine.b -> (combine.a, combine.b))
I'm using foo.bar
to mean the type variable bar
from the definition of foo
. Next we feed this into origFunc
which as the type (a, b) -> c
. Now when we try to fit this into .
we get
(.).b ~ my_curry.(a, b)
(.).c ~ my_curry.c
But wait! b
can't be both (a, b)
and b -> (a, b)
and thus the type error.
Instead we have two choices, we can create a new type of composition
(..) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
f .. g = \a b -> f (g a b)
Notice how this allows g
to take two arguments, and your function becomes
my_curry origFunc = combine .. origFunc
Or we can just use currying
my_curry origFunc x y = origFunc (x, y)
Upvotes: 6