Say, we want to introduce the notion of sum of functions of different arguments (let's call it < >
), which behaves like the that: (f1 < > f2)(x1, x2) == f1(x1) f2(x2)
.
While this can be easily written out manually, it makes sense to use point-free style with the help of the notion of cartesian product of functions. The latter is defined below and seems alright and quite general to me:
x :: (x1 -> y1) -> (x2 -> y2) -> (x1 -> x2 -> (y1, y2))
x f1 f2 = \x1 x2 -> (f1(x1), f2(x2))
Then we can write:
(< >):: Num a => (a -> a) -> (a -> a) -> (a -> a -> a)
(< >) = (uncurry ( )) . x
And the code above seems fine to me too, but GHC thinks otherwise:
* Couldn't match type: (x20 -> y20) -> a -> x20 -> (a, y20)
with: ((a -> a) -> a -> a -> a, (a -> a) -> a -> a -> a)
Expected: (a -> a)
-> ((a -> a) -> a -> a -> a, (a -> a) -> a -> a -> a)
Actual: (a -> a) -> (x20 -> y20) -> a -> x20 -> (a, y20)
* Probable cause: `x' is applied to too few arguments
In the second argument of `(.)', namely `x'
In the expression: (uncurry ( )) . x
In an equation for `< >': (< >) = (uncurry ( )) . x
* Relevant bindings include
(< >) :: (a -> a) -> (a -> a) -> a -> a -> a
It feels like the compiler cannot infer the second function's type, but why? And what am I supposed to do, is this even possible to do?
CodePudding user response:
If you supply two arguments, you will see what has gone wrong.
(< >) = uncurry ( ) . x
(< >) a = (uncurry ( ) . x) a
= uncurry ( ) (x a)
(< >) a b = uncurry ( ) (x a) b
Whoops! That b
gets passed to uncurry
as a third argument, rather than x
as a second argument as you probably intended. The third and fourth arguments are also supposed to go to x
rather than uncurry
, as in:
(< >) a b c d = uncurry ( ) (x a b c d)
Here's the correct way to point-free-ify a four-argument composition.
\a b c d -> f (g a b c d)
= \a b c d -> (f . g a b c) d
= \a b c -> f . g a b c
= \a b c -> ((.) f . g a b) c
= \a b -> (.) f . g a b
= \a b -> ((.) ((.) f) . g a) b
= \a -> (.) ((.) f) . g a
= \a -> ((.) ((.) ((.) f)) . g) a
= (.) ((.) ((.) f)) . g
Most people then write this with section syntax as (((f .) .) .) . g
. Applying this new fact to your case:
\a b c d -> uncurry ( ) (x a b c d)
= (((uncurry ( ) .) .) .) . x
CodePudding user response:
The .
operator is only for composing functions with a single argument, but the function x
has four arguments, so you have to use .
four times:
(< >) = (((uncurry ( ) .) .) .) . x
Do keep in mind that this is not considered good style in actual code.
CodePudding user response:
Define
compose2 :: (b -> c -> t) -> (a -> b) -> (d -> c) -> a -> d -> t
compose2 p f g x y = p (f x) (g y)
Now, compose2 ( )
is your < >
:
> :t compose2 ( )
compose2 ( ) :: Num t => (a -> t) -> (d -> t) -> a -> d -> t
As you can see its type is a bit more general than you thought.
compose2
already exists.