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
.
g :: a -> b -> c
,h :: d -> b
,j :: d -> a
, andx :: d
are all independent arguments tof
; their order implies nothing about how we might end up using them in the definition off
.To start, we know that
f
uses its arguments to return a value of typec
. But none of the arguments have a value of typec
; the only way to get a value of typec
is to useg
. But in order to useg
, you need arguments of typea
and typeb
, and none off
's arguments have those types. But we could useh
andj
to get them, if we had an argument of typed
to apply them to, and lo and behold, we do have a value of typed
: the argumentx
!.which can be flattened to the original answer of
If you want to think of the return value of
f
as beingd -> c
, rather than justc
, you can eliminatex
from the definition with some point-free trickery.You can even go a little further to remove
h
andj
as arguments, but the result, though simple, is even more incomprehensible:Moral of the story: sometimes point-free style abstracts away distracting details, other times it completely obscures the meaning of the function.