最近我不得不思考一些与你的问题非常相似的问题。以下是我发现的概括。
首先,像Tinctorius指出的那样,这很容易做到:
f2m :: Functor f => f (a -> b) -> a -> f b
f2m f a = fmap ($a) f
但是一般情况下这是不可能做到的:
m2a :: Monad m => (a -> m b) -> m (a -> b)
有一种深刻的理解方式是,有人在 #haskell irc 频道中很好地向我解释了,如果存在一个 m2a 函数,则 Applicative 和 Monad 没有区别。为什么呢?嗯,我不完全明白,但大概是这样的:Monad m => a -> m b 是具有一个参数的常见 monadic 操作类型,而 Applicative f => f (a -> b) 则是所谓的 “可应用 applicatives”的另一种常见类型(由于不知道正式名称,称之为“可适用applicatives”)。Monad 可以做到 Applicative 做不到的事情,这与 m2a 无法存在有关。
现在,应用到你的问题上:
joinFuncs :: (a -> [b]) -> [a -> b]
我怀疑同样的“Monad /= Applicative”论点(再次强调,我不完全理解)应该适用于这里。我们知道
Monad []
实例可以做
Applicative []
实例无法做到的事情。如果您可以写一个指定类型的
joinFuncs
,那么
[a -> b]
的结果在某种意义上必须与
a -> [b]
的参数“失去信息”,因为否则
Applicative []
将与
Monad []
相同。(通过“失去”信息,我的意思是任何具有
joinFuncs
类型的函数都不能具有反函数,因此它保证消除一些函数对
f, g :: a -> [b]
之间的区别。极端情况是
joinFuncs = undefined
。)
我发现我需要类似
m2a
的函数。所以我发现的特殊情况是可以这样做:
import Data.Map (Map)
import qualified Data.Map as Map
boundedM2a :: Monad m => (a -> m b) -> [a] -> m [(a,b)]
boundedM2a f = mapM f'
where f' a = do b <- f a
return (a, b)
boundedM2a' :: (Monad m, Ord a) => (a -> m b) -> [a] -> m (Map a b)
boundedM2a' f = liftM Map.fromList . boundedM2a f
请注意,除了我们需要枚举 a
的要求之外,有趣的观察结果是,为了做到这一点,我们必须在某种意义上“实现”结果;将其从函数/操作转化为列表、映射或表格。
Applicative f => Monad f
:每个f (a -> b)
都可以转换为(a -> f b)
,但不一定反过来(此外,你可以通过(=<<) :: (a -> f b) -> (f a -> f b)
的方式实现(<*>) :: f (a -> b) -> (f a -> f b)
,但并非总是如此)。虽然对此不太确定。 - user824425