简体   繁体   中英

Is there a standard function that computes `f x (g x)`?

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 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀

See https://wiki.haskell.org/Pointfree .

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM