basic_bgnr
basic_bgnr

Reputation: 737

implementing curry function

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

Answers (2)

bstamour
bstamour

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

daniel gratzer
daniel gratzer

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

Related Questions