This question provides a nice opportunity to collect information about this function that is scattered across multiple Q&As around here. Since it doesn't really have a standard name, I will just call it shift
like you did.
As Noughtmare points out, one way in which shift
arises is as a specialisation of distribute
:
distribute :: (Distributive g, Functor f) => f (g a) -> g (f a)
shift :: Distributive g => (r -> g a) -> g (r -> a)
shift = distribute @_ @((->) _)
If we instead specialise g
, the other functor in the type of distribute
, to a function functor, we get a combinator variously known as flap
or (??)
:
flap :: Functor f => f (s -> a) -> (s -> f a)
flap = distribute @((->) _)
-- flap m s = (\f -> f s) <$> m
(If we do both specialisations at once, we end up with flip
from the Prelude.)
Since distribute . distribute = id
, shift
and flap
are full inverses:
flap . shift = id
shift . flap = id
Given a distributive functor g
, shift
and flap
therefore give us an isomorphism between Kleisli arrows a -> g b
and static arrows g (a -> b)
. That reflects how the monad and applicative instances of a distributive functor are ultimately equivalent. Such a fact is more readily verified for the function functor, and extends to the other distributives through the Representable
isomorphism alluded to by Noughtmare's answer. (By the way, all distributive functors are indeed monads, even though that is not obvious from looking at Data.Distributive
given how the API of said module is currently laid out.)
Lastly, while shift
is a specialisation of distribute
, it is possible to turn things around and express distribute
in terms of shift
:
distribute m = (\p -> p <$> m) <$> shift id
We can think of shift id :: Distributive g => g (g a -> a)
as holding at each position of the distributive functor shape a g a -> a
extractor for that position, which is bound to p
in the definition above. That being so, mapping over shift id
makes it possible to pick values from matching positions within m :: f (g a)
.