It is not clear to me why the function defined as
f g x = g . g x
has the type
f :: (b -> a -> b) -> b -> a -> a -> b
I would have thought it would be of type
f :: (t -> t) -> t -> t
Can anyone explain to me how the expression is broken down? Thanks!
f of g of x is also known as a composite function and it is mathematically denoted as f(g(x)) or (f ∘ g)(x) and it means that x = g(x) should be substituted in f(x). It is also read as "f circle g of x". It is an operation that combines two functions to form another new function.
f ◦ g is the composition function that has f composed with g. Be aware though, f ◦ g is not the same as g ◦ f. (This means that composition is not commutative).
Note that function application has the highest priority; operators come later.
So, the term g . g x
first applies g
to x
, and then composes the result and g
itself. If x
has type b
, g
must have type b -> c
. Since we compose g
with g x
(the latter of type c
), c
must be a function type returning b
, so c = a -> b
. Now, the type of g
is b -> a -> b
and the type of g . g x
is a -> (a -> b)
; the type of f
happens to be (b -> a -> b) -> b -> a -> a -> b
.
If you wanted something like (a -> a) -> a -> a
instead, you could try one of this
f g x = g (g x)
f g x = (g . g) x
f g x = g . g $ x
f g = g . g
The idea is about understanding the (.)
operator, it has a type of
(.) :: (b -> c) -> (a -> b) -> a -> c
It takes two functions each with one parameter and compose them, after applying g x
the compiler assumed g
is actually g :: a -> b -> c
in order to satisfy the signature of (.) :: (b -> c) -> (a -> b) -> a -> c
which takes two functions with one argument. Otherwise the code won't compile.
And finally if you want the signature f :: (t -> t) -> t -> t
you need something like this:
λ> let applyTwice g = g.g
λ> :t applyTwice
applyTwice :: (a -> a) -> a -> a
λ> applyTwice (*2) 3
12
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