I am learning Haskell. I\'m sorry for asking a very basic question but I cant seem to find the answer. I have a function f defined by :
f x = g x x
>
I got here by pure chance, and I want to offer my solution, as nobody has mentioned lifting yet in this thread, not explicitly at least.
This is a solution:
f = liftM2 g id id
How to look at it?
g
has type a -> a -> b
, i.e. it takes two values of some type (the same type for both, otherwise the definition the OP gave of f
wouldn't make sense), and gives back another value of some type (not necessarily of the same type as the arguments);
lift2M g
is the lifted version of g
and it has type (Monad m) => m a -> m a -> m b
: it takes two monadic values, which are each a value in a so-far-unspecified context, and gives back a monadic value;
when passing two functions to liftM2 g
, the die is cast on what the context of the Monad
is: it is that the values are not in there yet, but will eventually be, when the function will receive the arguments it needs; in other words, functions are monads that store their own future values; therefore, lift2M g
takes in input two functions (or, the future values of two functions), and gives back the another function (or, its future value); knowing this, its type is the same as above if you change m
to (->) r
, or r ->
: (r -> a) -> (r -> a) -> (r -> b)
the two functions that we pass are both id
, which promises it'll give back the same value it receives;
liftM2 g id id
is therefore a function of type r -> b
that passes its argument to those two id
s, which let it unchanged and forward it to g
.
In a similar fashion, one can exploit that functions are applicative functors, and use this solution:
f = g <$> id <*> id