可折叠的一个例子,它不是一个Functor(或不是Traversable)?

时间:2011-12-02 16:06:05

标签: haskell functor fold traversal

Foldable实例可能是某种容器,因此也可能是Functor。确实,this

  

Foldable类型也是一个容器(虽然该类在技术上不需要Functor,但有趣的Foldable都是Functor s。

那么Foldable的例子是Functor还是Traversable? (也许是Haskell维基页错过了:-))

3 个答案:

答案 0 :(得分:51)

这是一个完全参数化的例子:

data Weird a = Weird a (a -> a)

instance Foldable Weird where
  foldMap f (Weird a b) = f $ b a

Weird不是Functor,因为a出现在负面位置。

答案 1 :(得分:47)

这是一个简单的例子:Data.Set.SetSee for yourself.

如果您检查为fold定义的专用mapSet函数的类型,原因应该是显而易见的:

foldr :: (a -> b -> b) -> b -> Set a -> b

map :: (Ord a, Ord b) => (a -> b) -> Set a -> Set b

由于数据结构在内部依赖于二叉搜索树,因此元素需要Ord约束。 Functor实例必须允许任何元素类型,因此这不可行,唉。

另一方面,折叠总是会破坏树以产生汇总值,因此无需对折叠的中间结果进行排序。即使折叠实际上构建了一个新的Set,满足Ord约束的责任在于传递给折叠的累积函数,而不是折叠本身。

同样可能适用于任何不完全参数化的容器类型。考虑到Data.Set的效用,我认为你引用的关于“有趣”Foldable的评论似乎有点可疑!

答案 2 :(得分:23)

阅读Beautiful folding 我意识到任何Foldable都可以通过将Functor包装到

中而成为data Store f a b = Store (f a) (a -> b)
store :: f a -> Store f a a
store x = Store x id

使用简单的智能构造器:

instance Functor (Store f a) where
    fmap f (Store x g)   = Store x (f . g)

instance (F.Foldable f) => F.Foldable (Store f a) where
    foldr f z (Store x g)    = F.foldr (f . g) z x

(这只是Store comonad数据类型的变体。)

现在我们可以定义

Data.Set.Set

这样,我们可以让Weird和Sjoerd Visscher的fmap成为一个仿函数。 (但是,由于结构不会记住它的值,如果Store中使用的函数很复杂,反复折叠它可能效率非常低。)


更新:这也提供了一个结构的示例,该结构是一个可折叠但不可遍历的仿函数。要使(->) r遍历,我们需要使sequenceA :: Applicative f => (r -> (f a)) -> f (r -> a) 遍历。所以我们需要实现

Either b

fsequenceA' :: (r -> Either b a) -> Either b (r -> a) 。然后我们需要实现

sequenceA

显然,没有这样的功能(您可以使用Djinn进行验证)。所以我们既不会意识到{{1}}。