Haskell 如何实现这种可遍历的使用模式?

Haskell 如何实现这种可遍历的使用模式?,haskell,traversal,applicative,Haskell,Traversal,Applicative,当使用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)) -&g

当使用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
但是我无法通过
遍历
序列a
fmap
来实现这一点。也许我需要更强的类型类约束?我真的需要一个
Monad

更新

具体地说,我想知道,我是否可以为一个
f
定义
fmapInner
,它适用于任何
可遍历的t
,以及一些直觉法则(我还不知道这些法则应该是什么),这是否意味着
f
东西是一个
单子
?因为,对于
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并翻转所有对。以前我认为它是
mapacumr
,但实际上是
mapacuml
traverseF

一样工作,现在我确信这是不可能的。这就是为什么

 tF ::(Applicative f, Traversable t) => (f a -> f b) -> f (t a) -> f (t b)
因此,我们有一个副作用计算,返回
ta
,我们想用它来确定发生了什么副作用。换句话说,type
ta
的值将决定当我们应用
遍历时会发生什么副作用

但是,对于应用程序类型类,这是不可能的。我们可以动态地选择值,但out计算的副作用是静态的。要明白我的意思

pure :: a -> f a -- No side effects
(<*>) :: f (a -> b) -> f a -> f b -- The side effects of `f a` can't
                                  -- decide based on `f (a -> b)`.
因为这样我们就可以简单地做到

smash $ (f :: a -> f a) <$> (fa :: f a) :: f a

但它们分别是
join
>=
,是
Monad
typeclass的成员。所以,是的,你需要一个单子(

此外,还提供了一个带有monad约束的函数的漂亮的无点实现

traverseM = (=<<) . mapM . (.return)

您在
fmapInner
中要求的类型在我看来与
traverseF
的类型大不相同。也许您更喜欢
foo::(a->fb)->(ta->f(tb))
或类似的东西,在这种情况下,它只是
遍历
。然后
f
可以专门处理
状态s
,基本上给你提供
traverseF
的类型。在重读时,我确信我并不真正理解你的要求。所以请忽略我之前的评论,但我会离开我明白你的意思,我也明白你刚才指出的事情。我已经知道我可以编写像你这样的函数;但是,在我看来,定义一个可重用函数
fa->fb
,然后用它将a
f(ta)
转换成
f(tb)似乎很自然
,除非我假设
f
是一个
Monad
,否则似乎没有好的方法可以这样做。你认为
(,)s
应用实例是什么(我们必须把
s
放在第一位,因为我们没有为类型定义
翻转
)。我不是说
(,)s)
目前是
Applicative
的一个实例,但是如果您愿意,我们可以定义一个
newtype
来实例化它。重点是类型签名模式,而不是具体的类型。我试着按照您对
pure
bind
的评论,但我认为我不太了解它们。您能理解吗给他们更多解释一下?
smash $ (f :: a -> f a) <$> (fa :: f a) :: f a
traverseF f t = smash $ traverse (f . pure) <$> t
bind :: m a -> (a -> m b) -> m b -- and it's obvious how `a -> m b`
                                 -- can choose side effects.
traverseF f t = bind t (traverse $ f . pure)
traverseM = (=<<) . mapM . (.return)
traverseF :: (Applicative f,Traversable t) => (f a -> f b) -> t a -> f (t a)
traverseF = traverse . (.pure)