For example, I can't do
f = ((*2).(+)) 3
which is alright since I can always do
f = (*2).(+3)
but this is slightly inconvenient when I want to create a list of functions, e.g.
map ((*2).(+)) [1, 2, 3]
whereas
map (+) [1, 2, 3]
would be alright.
Of course, I can always use lambda notation to implement currying:
map (\x y -> 2*(x + y)) [1, 2, 3]
As far as I can tell, GHC doesn't like composing partially applied functions because it doesn't know how to feed function types to operations like (*2).
(+) 2 :: Num a => a -> a
(*2) :: Num a => a -> a
But I've always thought it should be a rather natural thing: the type of the output of (+) is Num a => a, so (*2) should be able to 'eat' that.
My question is: is this implemented in some way? Or, does someone have any idea why such a straightforward thing isn't implemented in Haskell?
Partial application in Haskell involves passing less than the full number of arguments to a function that takes multiple arguments.
Composing functions is a common and useful way to create new functions in Haskell. Haskell composition is based on the idea of function composition in mathematics. In mathematics, if you have two functions f(x) and g(x), you compute their composition as f(g(x)). The expression f(g(x)) first calls g and then calls f.
In computer science, partial application (or partial function application) refers to the process of fixing a number of arguments to a function, producing another function of smaller arity. Given a function , we might fix (or 'bind') the first argument, producing a function of type .
Currying tends to produce nested unary(1-ary) functions. However, the transformed functions are still broadly similar to the original one. Partial application tends to produce functions that have an arbitrary number of arguments, and the transformed functions usually have a lot of differences from the original one.
Haskell support composition of partial functions but you have type mismatch. Composition is function
(.) :: (b -> c) -> (a -> b) -> a -> c
In your case you have two function
(*2) :: Num a => a -> a
(+) :: Num a => a -> a -> a
and when you compose this functions type of result will be
((*2).(+)) :: (Num (a -> a), Num a) => a -> a -> a
that not what you want. You can rewrite your function f
such as (.) (*2) . (+)
but I think that lambda is more readable.
And you confuse partial function and partial application. Partial function is function that defined not for the entire domain and partial application is the process of fixing a number of arguments to a function, producing function of smaller arity.
When going to point-free it might get confusing. If we go through the type signatures;
(.)
is (b -> c) -> (a -> b) -> a -> c
(+)
is Num a => a -> a -> a
(2*)
is Num a => a -> a
Now if we do (2*) . (+)
being the second parameter of (.)
which is (+)
, has to have a type (a -> b)
which is in fact true when we rewrite (+)
s type as Num a => a -> (a -> a)
. So our b
type happens to be Num a => a -> a
. Now remember that (.)
takes (b -> c)
as first parameter. We have a little problem here because in our expression (2*) . (+)
(2*)
waits for a b
type like Num a => a
while we have our b
type like Num a => a -> a
. You can't multiply a function by 2..! We must transform (2*)
into such a function that would take a function of our type which is Num a => a -> a
, run it and feed it's result to (2*)
. No need to look this is no more than (.)
. In this case if we write again like ((2*) . )
we can safely feed our Num a => a -> a
type function (remember this is partially applied (+)
). Let us wrap it up...
Our point free equivalent of \x y -> 2*(x + y)
is ((2*) . ) . (+)
Prelude> (((2*) . ) . (+)) 3 5
16
We may use applicative functors of ((->) r)
type to express ourselves more easily in these situations. I will try to add it once i have more time.
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