我最近不得不考虑很多问题,这些问题简化为与您的问题非常相似的问题。这是我发现的概括。
首先,这样做很简单(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 之间就没有区别。为什么?好吧,我不是 100% 遵循它,但它是这样的:Monad m => a -> m b 是带有一个参数的非常常见的一元动作类型,而 Applicative f => f (a -> b) 也是非常常见的类型,因为不知道正确的名称,我称之为“适用的应用程序”。而Monad 可以做Applicative 不能做的事情这一事实与m2a 不存在的事实有关。
现在,应用于您的问题:
joinFuncs :: (a -> [b]) -> [a -> b]
我怀疑同样的“Monad /= Applicative”论点(再次强调,我不完全理解)应该适用于此。我们知道Monad [] 实例可以做Applicative [] 实例不能做的事情。如果您可以编写具有指定类型的joinFuncs,那么与a -> [b] 参数相比,[a -> b] 结果在某种意义上必须“丢失信息”,因为否则Applicative [] 与Monad [] 相同。 (我所说的“丢失”信息是指任何具有joinFuncs 类型的函数都不能有逆函数,因此可以保证消除某些函数对f, g :: a -> [b] 之间的区别。极端情况是@987654343 @.)
我确实发现我需要类似于m2a 的函数所以我发现的特殊情况是可以这样做:
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
请注意,除了我们枚举as 的要求之外,一个有趣的观察是,要做到这一点,我们必须在某种意义上“实现”结果;将其从函数/操作转换为某种列表、地图或表格。