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