Foldable
实例可能是某种容器,因此也可能是Functor
。确实,this说
Foldable
类型也是一个容器(虽然该类在技术上不需要Functor
,但有趣的Foldable
都是Functor
s。
那么Foldable
的例子是Functor
还是Traversable
? (也许是Haskell维基页错过了:-))
答案 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.Set
。 See for yourself.
如果您检查为fold
定义的专用map
和Set
函数的类型,原因应该是显而易见的:
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
让f
为sequenceA' :: (r -> Either b a) -> Either b (r -> a)
。然后我们需要实现
sequenceA
显然,没有这样的功能(您可以使用Djinn进行验证)。所以我们既不会意识到{{1}}。