2

使用するとき、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で はこれを実装できません。たぶん、より強い型クラスの制約が必要ですか? ここは絶対に必要ですか?sequenceAfmap<*>pureMonad

アップデート

具体的には、適用される直観の法則の一部で機能fmapInnerする aを定義できるかどうかを知りたいです(法則がどうあるべきかはまだわかりません) 。したがって、 for s の実装は簡単です。fTraversable tfMonadMonad

--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ます。

4

1 に答える 1

2

私は今、これは不可能だと確信しました。理由は次のとおりです。

 tF ::(Applicative f, Traversable t) => (f a -> f b) -> f (t a) -> f (t b)

したがって、返されるこの副作用計算がt aあり、これを使用して、どのような副作用が発生するかを判断したいと考えています。つまり、 type の値によって、t a適用時にどのような副作用が発生するかが決まりますtraverse

ただし、これは適用型クラスでは不可能です。動的に値を選択できますが、アウト計算の副作用は静的です。私が何を意味するかを見るために、

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)`.

以前の値に応じて副作用を判断するには、2 つの考えられる方法があります。

smash :: f (f a) -> f a

そうすれば、簡単にできるからです

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)

しかし、これらは型クラスのメンバーであり、それぞれjoinです。そうです、モナドが必要です。:(>>=Monad

また、モナド制約を使用した関数の素敵で無意味な実装は次のとおりです。

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

編集、

特筆すべきだと思います

traverseF :: (Applicative f,Traversable t) => (f a -> f b) -> t a -> f (t a)
traverseF = traverse . (.pure)
于 2013-10-11T02:53:39.770 に答える