I'm trying to define a simple Haskell function with the type (m -> n -> l) -> (m -> n) -> m -> l.
I thought that it needs be to defined as f g h x = f g (h x), but apparently that's not true. How could I correct this function?
Based on the signature, the only sensical implementation is:
f :: (m -> n -> l) -> (m -> n) -> m -> l
f g h x = g x (h x)
This makes sense since we are given two functions g :: m -> n -> l and h :: m -> n, and a value x :: m. We should construct a value with type l. The only way to do this is to make use of the function g. For the parameter with type m we can work with x, for the second parameter we need a value of type n, we do not have such value, but we can construct one by applying h on x. Since h x has type h x :: n, we thus can use this as second parameter for g.
This function is already defined: it is a special case of (<*>) :: Applicative f => f (n -> l) -> f n -> f l with f ~ (->) m.
Djinn is a tool that reasons about types and thus is generating function definitions based on its signature. If one queries with f :: (m -> n -> l) -> (m -> n) -> m -> l, we get:
f :: (m -> n -> l) -> (m -> n) -> m -> l
f a b c = a c (b c)
which is the same function (except that it uses other variable names).
f :: (m -> n -> l) -> (m -> n) -> m -> l
f g h x = _
Now you need to use the arguments in some way.
g (_ :: m) (_ :: n) :: l
h (_ :: m) :: n
x :: m
Both g and h need a value of type m as their first argument. Well, luckily we have exactly one such value, so it's easy to see what to do.
g x (_ :: n) :: l
h x :: n
x :: m
So now g still needs a value of type n. Again we're lucky, because applying h to x has produced such a value.
g x (h x) :: l
h x :: n
x :: m
Ok, and there we now have something of type l, which is what we needed!
f g h x = g x (h x)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With