3
votes

I have to convert a Haskell type signature into a term. The type signature is :

f :: (a -> b -> c) -> (d -> b) -> (d -> a) -> d -> c

The correct resulting term is :

f g h j x = g (j x) (h x)

and here lies my problem as I understand it g is a function which returns a function which returns c and c is function which returns a function d which returns b and b is a function which returns itself which then returns itself again which then returns c.

Correct me if i am wrong.

What I don't get is why is g taking (j x) as first argument and (h x) as second argument. Shouldn't it be the other way around? Haskell is right associative and h is the secound parameter given to the function f and not j.

1
"c is function" - why? Parentheses matter: a -> b -> c is a complete signature. It's a function that takes a and returns another function that takes b and returns c. Then (d -> b) is the second argument to f.ForceBru
One does not “convert” a type signature into a term. What you do is, you implement a term of that type. In general there is not just one right way to do that (though in simple examples like this one, it may well be that all possible implementations are equivalent).leftaroundabout

1 Answers

5
votes

g :: a -> b -> c, h :: d -> b, j :: d -> a, and x :: d are all independent arguments to f; their order implies nothing about how we might end up using them in the definition of f.

To start, we know that f uses its arguments to return a value of type c. But none of the arguments have a value of type c; the only way to get a value of type c is to use g. But in order to use g, you need arguments of type a and type b, and none of f's arguments have those types. But we could use h and j to get them, if we had an argument of type d to apply them to, and lo and behold, we do have a value of type d: the argument x!.

f g h j x = let aValue = j x
                bValue = h x
                cValue = g aValue bValue
            in cValue

which can be flattened to the original answer of

f g h j x = g (j x) (h x)

If you want to think of the return value of f as being d -> c, rather than just c, you can eliminate x from the definition with some point-free trickery.

f g h j = g <$> j <*> h  -- liftA2 g j h

You can even go a little further to remove h and j as arguments, but the result, though simple, is even more incomprehensible:

f = flip . liftA2

Moral of the story: sometimes point-free style abstracts away distracting details, other times it completely obscures the meaning of the function.