I couldn't find anything on Hoogle, but is there a standard function or operator with a signature like:
func :: (a -> b -> c) -> (a -> b) -> a -> c
Ie given two functions f
and g
and an element x
as arguments it computes fx (gx)
?
The function you're looking for is (<*>)
. Why? Well, it's true that (<*>)
has a more general type:
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
But consider that we can specialize f
to (->) r
, which has an Applicative
instance:
(<*>) :: (->) r (a -> b) -> (->) r a -> (->) r b
…then we can rearrange the type so ->
is infix instead of prefix, as it normally is:
(<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)
…which is the same as your signature modulo alpha renaming.
This works because the function type, (->)
, has instances of Functor
, Applicative
, and Monad
, which are idiomatically called “reader”. These instances thread an extra argument around to all their arguments, which is exactly what your function does.
f <*> g
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
Yes, this is a special case of ap :: Monad m => m (a -> b) -> ma -> mb
Here you should see the monad m
as (->) r
, so a function with a parameter. Now ap
is defined as [source] :
ap m1 m2 = do
x1 <- m1
x2 <- m2
return (x1 x2)
Which is thus syntactical sugar for:
ap m1 m2 = m1 >>= (\x1 -> m2 >>= return . x1)
The bind function >>=
is defined for a (->) r
instance as [source] :
instance Monad ((->) r) where
f >>= k = \ r -> k (f r) r
return = const
( return
is by default equal to pure
, which is defined as const
).
So that means that:
ap f g = f >>= (\x1 -> g >>= const . x1)
= f >>= (\x1 -> (\r -> (const . x1) (g r) r))
= \x -> (\x1 -> (\r -> (const . x1) (g r) r)) (f x) x
now we can perform a beta reduction ( x1
is (fx)
):
ap f g = \x -> (\r -> (const . (f x)) (g r) r) x
and another beta reduction ( r
is x
):
ap f g = \x -> (const . (f x)) (g x) x
We can unwrap the const
as \\c _ -> c
, and (.)
as f . g
f . g
to `\\z -> f (gz):
ap f g = \x -> ((\c _ -> c) . (f x)) (g x) x
= \x -> (\z -> (\c _ -> c) ((f x) z)) (g x) x
Now we can again perform a beta reductions ( z
is (gx)
, and c
is ((fx) (gx))
):
ap f g = \x -> ((\c _ -> c) ((f x) (g x))) x
= \x -> (\_ -> ((f x) (g x))) x
finally we perform a beta-reduction ( _
is x
):
ap f g = \x -> ((f x) (g x))
We now move x
to the head of the function:
ap f g x = (f x) (g x)
and in Haskell fxy
is short for (fx) y
, so that means that:
ap f g x = (f x) (g x)
= f x (g x)
which is the requested function.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.