使用时Data.Traversable
,我经常需要一些代码,例如
import Control.Applicative (Applicative,(<*>),pure)
import Data.Traversable (Traversable,traverse,sequenceA)
import Control.Monad.State (state,runState)
traverseF :: Traversable t => ((a,s) -> (b,s)) -> (t a, s) -> (t b, s)
traverseF f (t,s) = runState (traverse (state.curry f) t) s
遍历结构并建立一个由某种状态驱动的新结构。我注意到类型签名模式并相信它可以概括为
fmapInner :: (Applicative f,Traversable t) => (f a -> f b) -> f (t a) -> f (t b)
fmapInner f t = ???
traverse
但我无法用, sequenceA
,fmap
和<*>
来实现这一点pure
。也许我需要更强的类型类约束?我绝对需要Monad
这里吗?
更新
具体来说,我想知道我是否可以定义fmapInner
适用f
于任何Traversable t
适用于直觉的法则和一些适用于直觉的法则(我还不知道法则应该是什么),这是否暗示f
事物是 a Monad
?因为,对于Monad
s,实现是微不足道的:
--Monad m implies Applicative m but we still
-- have to say it unless we use mapM instead
fmapInner :: (Monad m,Traversable t) => (m a -> m b) -> m (t a) -> m (t b)
fmapInner f t = t >>= Data.Traversable.mapM (\a -> f (return a))
更新
感谢您的出色回答。我发现我traverseF
的只是
import Data.Traversable (mapAccumL)
traverseF1 :: Traversable t => ((a, b) -> (a, c)) -> (a, t b) -> (a, t c)
traverseF1 =uncurry.mapAccumL.curry
没有明确使用 Monad.State 并且所有对都翻转了。以前我虽然是这样,mapAccumR
但实际上它是mapAccumL
这样工作的traverseF
。