我有这段代码:
fmapM :: Monad m => (a -> m b) -> (t, a) -> m (t, b)
fmapM f (id, e) = do
ev <- f e
return (id, ev)
基本上将函数应用于元组中的第二个元素,然后“提取”monad。 由于元组是一个函子,有没有办法为所有函子推广这个?我想不出一个实现,但类型签名应该是:
fmapM :: (Monad m, Functor f) => (a -> m b) -> f a -> m f b
似乎第二步是“序列”操作,它从另一个仿函数(列表)中提取monad。但序列并不适用于所有仿函数。你能想出一个fmapM的通用实现吗?
编辑:我意识到旧版本的拥抱确实已经实现了这个功能。但是,我找不到代码。现在,建议我使用foldable / traversable来实现相同的目标。
答案 0 :(得分:11)
您正在寻找的功能是traverse
,来自Data.Traversable
:
traverse :: (Applicative f, Traversable t) => (a -> f b) -> t a -> f (t b)
请注意,您不能traverse
任何Functor
- 例如(r ->)
- 所以Traversable
仿函数有一个单独的子类。另请注意,您不需要Monad
- 只需Applicative
(这种推广很有用)。