traverse
default定義として、よくtraverseが定義される
定義
code:hs
traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
traverse f = sequenceA . fmap f
データ構造tと計算コンテナfを入れ替えている
a -> f bにt aを適用するとt (f b)になるはずだが、
結果は、データ構造tと計算コンテナfを入れ替えて、f (t b)になる
直観的な理解
定義を見れば明らかだが
code:_
t a
↓ map (a -> f b)
t (f b)
↓ sequence
f (t b)
上記の定義をListに対して書き換えてみると以下のように書ける
code:hs
traverse f [] = pure []
traverse f (x:xs) = (:) <$> f x <*> traverse f xs
いくつかの型での定義を見る
List
code:hs
traverse :: Applicative f => (a -> f b) -> a -> f b traverse f [] = pure []
traverse f (x:xs) = (:) <$> f x <*> traverse f xs
実際はfoldrを使ってもっとスマートに定義されているが同じ意味
code:hs
traverse f = foldr (\x ys -> (:) <$> f x <*> ys) (pure [])
Maybe
code:hs
traverse :: Applicative f => (t -> f a) -> Maybe t -> f (Maybe a)
traverse _ Nothing = pure Nothing
traverse f (Just x) = Just <$> f x
Either
code:hs
traverse :: Applicative f => (t -> f b) -> Either a t -> f (Either a b)
traverse _ (Left x) = pure (Left x)
traverse f (Right y) = Right <$> f y
どれも以下のような感じで定義されていることがわかる
code:hs
traverse f ... = pure データ構成子
traverse f ... = データ構成子 <$> f x1 (または traverse f xs1)
<*> f x2 (または traverse f xs2)
...
<*> f xn (または traverse f xsn)
参考