除了可折叠之外,Traversable还有什么“独特的方法”?

时间:2014-01-13 01:25:52

标签: haskell containers fold

FoldableTraversable的超类,类似于FunctorApplicativeMonad的超类的方式。

类似于Monad的情况,可以基本上实现fmap

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

我们也可以将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))

使用Monoid m => (,) m monad。因此,超类和方法的组合在两种情况下都有一定的冗余。

如果是monads,可以认为类型类的“更好”定义是(我将跳过applicative / monoidal)

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

至少那是在类别理论中使用的。这个定义不使用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之间的区别。与Monad vs Functor非常相似:>>=对于日常Haskell编程比join更方便(因为您通常需要这个组合 fmapjoin),后者使得更容易掌握monad是什么。

2 个答案:

答案 0 :(得分:3)

FoldableFunctorTraversableMonad,即FoldableFunctorMonad的超类Traversable(模拟所有申请/ monad提案噪音)。

确实,这已经在代码中了

instance Foldable f => Traversable f where
  ...

所以,目前还不清楚还有什么需要。 Foldable的特点是toList :: Foldable f => f a -> [a],而Traversable最终不仅取决于能够像toList这样的列表抽象内容,还能够提取形状

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

取决于traverse

有关此媒体资源的详情,请参阅this blog post by Russell O'Connor

答案 1 :(得分: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

我认为此myTraversetraverse的行为相同,仅使用类ApplicativeFoldableMonoid。如果您想摆脱foldr,可以重新编写它以使用foldMap代替Monoid

列表很容易,因为它们是扁平结构。但是,我强烈怀疑你可以使用Zipper为任何结构获得正确的重建功能(因为拉链通常是可导出的,它们应该始终存在)。

但即使使用拉链,也没有任何方法可以指示monoid / function的结构。从理论上讲,似乎Traversable增加了类似

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

这似乎与Foldable重叠,但我认为在尝试将路径与其组成值相关联时,这是不可避免的。