Given value f
with type :: Applicative f => f (a -> b -> c)
, What's the best way to map arguments to the inner function.
So far I've found the following:
(\x -> x a b) <$> f
(flip ($ a) b) <$> f
($ b) <$> ($ a) <$> f
I guess my question is why Haskell doesn't have a :: a -> b -> (a -> b -> c) -> c
function. Or does it?
The Applicative
class has the <*>
operator (usually pronounced "ap", and is equivalent to Control.Monad.ap
for most Monad
s), which combined with the <$>
operator (itself just an infix alias for fmap
) lets you write code like
-- f :: a -> b -> c
-- fa :: Applicative f => f a
-- fb :: Applicative f => f b
f <$> fa <*> fb :: Applicative f => f c
If you need to apply pure arguments, then use the pure
method of the Applicative
class:
-- f :: a -> b -> c
-- a :: a
-- b :: b
f <$> pure a <*> pure b :: Applicative f => f c
An example might be
sumOfSquares :: Num a => a -> a -> a
sumOfSquares a b = a * a + b * b
> sumOfSquares <$> Just 1 <*> Just 2
Just 5
> sumOfSquares <$> Just 1 <*> Nothing
Nothing
> sumOfSquares <$> pure 1 <*> pure 2 :: Maybe Int
5
> sumOfSquares <$> readLn <*> readLn :: IO Int
1<ENTER>
2<ENTER>
5
The Applicative f => f (a -> b -> c)
is being constructed by f <$>
here, so if you already had something like
> let g :: IO (Int -> Int -> Int); g = undefined
Then you could just use it as
> g <*> pure 1 <*> pure 2
The <*>
operator has the type
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
so if your function has type x -> y -> z
, then a ~ x
and b ~ y -> z
, so repeated application of <*>
(get it?) passes more arguments to your wrapped function.
We've got
(<$>) :: Functor f => (a -> b) -> f a -> f b
But you want the opposite
(>$<) :: Functor f => f (a -> b) -> a -> f b
Which we can easily define:
(>$<) f a = ($a) <$> f
So given
f :: Functor f => f (a -> b -> c)
a :: a
b :: b
Then
f >$< a :: f (b -> c)
f >$< a >$< b :: f c
This isn't as idiomatic as <*>
, but it works for all Functor
s, not just Applicative
s, which is nice.
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