Consider functions of type a -> b -> c
, and the applicative values a1, a2 :: (Applicative f) => f a
.
I wish to construct a function which may be applied to functions of type a -> b -> c
to obtain values of type Applicative f :: f c
. I can do this in the following way:
g :: (Applicative f) => (a -> b -> c) -> f c
g = \f -> f <$> a1 <*> a2
(The explicit lambda is deliberate, as I am considering the construction of this function at any level, not just the top level).
If I try to write g
in point-free style:
g = (<$> a1 <*> a2)
I get the following compile error:
The operator `<$>' [infixl 4] of a section
must have lower precedence than that of the operand,
namely `<*>' [infixl 4]
in the section: `<$> gen1 <*> gen2'
I could write this point-free implementation:
g = flip (flip liftA2 a1) a2
but I feel that this is less readable, and it is simpler to refactor the infix function-based implementation to, e.g., add another argument, than changing the above to use liftA3
.
One can write a chain of compositions:
g = (<*> a2) . (<$> a1)
This achieves point-free style and it is simple to add arguments - but they get prepended on the left instead of appended on the right, so you lose the correspondence with the function type (a -> b -> c)
. Furthermore, with more arguments you end up with a much longer expression than just using a lambda as in the first implementation.
So, is there are nice, terse way to write the section I desire, or am I stuck with a lambda?
They are equivalent, in practice.
Definition. In Haskell, an applicative is a parametrized type that we think of as being a container for data of that type plus two methods pure and <*> . Consider a parametrized type f a . The pure method for an applicative of type f has type. pure :: a -> f a.
The expression fmap (*2) is a function that takes a functor f over numbers and returns a functor over numbers. That functor can be a list, a Maybe , an Either String, whatever. The expression fmap (replicate 3) will take a functor over any type and return a functor over a list of elements of that type.
Haskell provides special syntax to support infix notation. An operator is a function that can be applied using infix syntax (Section 3.4), or partially applied using a section (Section 3.5).
<*>
operates on the result of <$>
, so:
g = (<*> a2) . (<$> a1)
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