2014-01-13 4 views
8

FoldableFunctorApplicativeMonadのスーパークラスであるのと同様にTraversableのスーパークラスです。Foldableに加えてTraversableが持つ「別個の方法」は何でしょうか?

基本的に、我々はまた Monoid m => (,) mモナドを用い foldMap

foldLiftT :: (Traversable t, Monoid m) => (a -> m) -> t a -> m 
foldLiftT f = fst . traverse (f >>> \x -> (x,x)) 
      -- or: . sequenceA . fmap (f >>> \x -> (x, x)) 

ようにエミュレートすることができ

liftM :: Monad m => (a->b) -> m a -> m b 
liftM f q = return . f =<< q 

としてfmapを実現することができるMonadの場合と同様に

。したがって、スーパークラスとメソッドの組み合わせは、どちらの場合も一定の冗長性を持ちます。モナドの場合

class (Functor m) => Monad m where 
    return :: a -> m a 
    join :: m (m a) -> m a 

が、少なくともそれは圏論で使われているものです(私は応用的/ monoidalをスキップします)型クラスの「より良い」の定義が可能と主張することができます。この定義では、Functorスーパークラスを使用せずに、ではありません。liftMであるため、この冗長性はありません。

Traversableクラスでも同様の変換が可能ですか?


明確にする:私が後だが再定義され、のはそれを呼びましょう、

class (Functor t, Foldable t) => Traversable t where 
    skim :: ??? 

、そのような私たちは、実際のTraverseメソッドを作ることができることを、トップレベルの機能

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

ですが、はありません。は一般的に

instance (Traversable t) => Foldable t where 
    foldMap = ... skim ... 

data T 
instance Traversable T where 
    skim = ... 

私はにはが必要なので、私は尋ねません。 FoldableTraversableの違いをよく理解するための概念的な質問です。ここでも多くのようなMonadFunctor対:(あなたは通常、まさにこの組み合わせfmapjoin必要があるため)>>=がはるかに便利日常のHaskellプログラミングのjoinよりもある一方で、後者はそれが単純なモナドが何であるかを把握することができます。

Foldable
+1

別の方法は「トラバース」です。 'Foldable'という言葉で実装することはできません。 –

+0

もちろん、そうではありませんが、 'Foldable'を' traverse'の形で実装することができます。 – leftaroundabout

+1

...これは、 'Foldable'が' Traversable'のスーパークラスである理由です。スーパークラスは、サブクラスに関して実装可能である必要があります。 –

答えて

3

TraversableとしてFunctorであるMonadである、すなわちFoldableFunctorMonadTraversableのスーパークラス(モジュロ全てモナド/応用的提案ノイズ)です。

確かに、それはそれはしたいためにそこにあるより何明確ではありません、

instance Foldable f => Traversable f where 
    ... 

だから、コードにすでにあります。TraversabletoListようなリストがないだけでなく、

shape :: Functor f => f a -> f() 
shape = fmap (const()) 

形状を抽出し、それらを

combine :: Traversable f => f() -> [a] -> Maybe (f a) 
combine f_ = evalStateT (traverse pop f_) where 
    pop :: StateT [a] Maybe a 
    pop = do x <- get 
      case x of 
      [] = empty 
      (a:as) = set as >> return a 
を再結合することができるよう抽象コンテンツすることができないだけに、最終的に依存しながら FoldabletoList :: Foldable f => f a -> [a]を特徴とします

これはtraverseに依存します。

このプロパティの詳細については、this blog post by Russell O'Connorを参照してください。

+0

'combine 'が' Traversable'の唯一のメソッドであれば、 'traverse' /' sequenceA'を定義することができますか? – leftaroundabout

+2

私はたぶんFoldableがFunctorに向いていると言いたいのは、Traversableが* Applicative *になっているからです。 –

+0

@leftaroundについて試してみてください。つまったらポストしてください:-) – misterbee

3

スーパーハンドウェイビーですので遅くなりますが、Traversable以上の余分な力はFoldable以上で元の構造を再現する方法です。たとえば、リストに:

module MyTraverse where 

import Data.Foldable 
import Data.Traversable 
import Control.Applicative 
import Data.Monoid 

data ListRec f x = ListRec 
    { el :: f (Endo [x]) 
    } 

instance Applicative f => Monoid (ListRec f x) where 
    mempty = ListRec (pure mempty) 
    mappend (ListRec l) (ListRec r) = 
     ListRec (mappend <$> l <*> r) 

toM :: Functor f => f b -> ListRec f b 
toM this = ListRec $ (Endo . (:)) <$> this 

fromM :: Functor f => ListRec f b -> f [b] 
fromM (ListRec l) = flip appEndo [] <$> l 

myTraverse :: Applicative f => (a-> f b) -> [a] -> f [b] 
myTraverse f xs = fromM $ foldMap (toM . f) xs 

私はこのmyTraverseはクラスのみApplicativeFoldable、およびMonoidを使用して、traverseと同じように振る舞うと思います。 Monoidを取り除きたい場合は、foldMapの代わりにfoldrを使用するように書き換えることができます。

リストはフラットな構造なので簡単です。しかし、ジッパーを使って構造体の適切な再構成関数を得ることができます(ジッパーは一般的に導き出せるので、常に存在するはずです)。

ジッパーでも、その構造をモノイド/機能に示す方法はありません。概念的に、それはそうTraversable

class Traversed t where 
    type Path t :: * 
    annotate :: t a -> [(Path t, a)] 
    fromKeyed :: [(Path t, a)] -> t a 

のようなものを追加し、これはFoldableと大きく重なっているようだが、私はそれらの構成値を使用してパスを関連付けるしようとすると、それは避けられないことだと思います。

関連する問題