I have recently had to think quite a bit about problems that reduce to a question very similar to yours. Here's the generalizations that I found.
First, it is trivial to do this (at Tinctorius pointed out):
f2m :: Functor f => f (a -> b) -> a -> f b
f2m f a = fmap ($a) f
But it is impossible to do this in general:
m2a :: Monad m => (a -> m b) -> m (a -> b)
One insightful way of understanding this, which somebody kindly explained to me in the #haskell irc channel, is that if there existed an m2a
function, there would be no difference between Applicative
and Monad
. Why? Well, I don't follow it 100%, but it's something like this: Monad m => a -> m b
is the very common type of monadic actions with one parameter, while Applicative f => f (a -> b)
is the also very common type of what, for not knowing the proper name, I'll call "applicable applicatives." And the fact that Monad
can do things that Applicative
cannot is tied to the fact that m2a
cannot exist.
So now, applied to your question:
joinFuncs :: (a -> [b]) -> [a -> b]
I suspect the same "Monad /= Applicative" argument (which, again, let me stress, I don't fully understand) should apply here. We know that the Monad []
instance can do things that the Applicative []
instance cannot. If you could write a joinFuncs
with the specified type, then the [a -> b]
result must in some sense "lose information" compared to the a -> [b]
argument, because otherwise Applicative []
is the same as Monad []
. (And by "lose" information I mean that any function with joinFuncs
's type cannot have an inverse, and thus it is guaranteed to obliterate the distinction between some pair of functions f, g :: a -> [b]
. The extreme case of that is joinFuncs = undefined
.)
I did find that I needed functions similar to m2a
So the special case that I found is that it's possible to do this:
import Data.Map (Map)
import qualified Data.Map as Map
-- | Enumerate a monadic action within the domain enumerated by the
-- argument list.
boundedM2a :: Monad m => (a -> m b) -> [a] -> m [(a,b)]
boundedM2a f = mapM f'
where f' a = do b <- f a
return (a, b)
-- | The variant that makes a 'Map' is rather useful.
boundedM2a' :: (Monad m, Ord a) => (a -> m b) -> [a] -> m (Map a b)
boundedM2a' f = liftM Map.fromList . boundedM2a f
Note that in addition to the requirement that we enumerate the a
s, an interesting observation is that to do this we have to "materialize" the result in a sense; turn it from a function/action into a list, map or table of some sort.
Applicative f => Monad f
: everyf (a -> b)
can be turned into a(a -> f b)
, but not necessarily the other way around (moreover, you can implement(<*>) :: f (a -> b) -> (f a -> f b)
in terms of(=<<) :: (a -> f b) -> (f a -> f b)
, but not always the other way around). Not sure about this, though. – Chartist