在this presentation [2005]中我们在幻灯片32中读到:
zipper数据类型隐藏了一个comonad。这正是人们所需要的 构建属性评估。
所以看来你可以表达Zippers in terms of Comonads。这甚至看起来possible in Scala。
查看zipper source,我们看到拉链表示为Clojure元数据。
我的问题是,有什么证据证明Clojure Zippers会因为表达为comonads而受益?
所以我们需要在原始组中获得所有可能的拉链!
答案 0 :(得分:8)
你问的问题有一些结构性的谬误。 Zippers 不能表示为Comonads,而是 本质上。
同样,整数只是是幺半群(以两种方式!),无论你是否选择接受这一事实。
所以,不要问你应该问什么好处是“我可以通过识别共同结构来提高清晰度吗?”
答案是“是的!”
Comonadic结构意味着在任何拉链上都存在两种有趣的方法。第一个是明显的,显然是有用的 - “这里”功能。为了使这更具体,我将制作一个列表拉链
data Zipper a = Zipper { before :: [a], here :: a, after :: [a] }
现在here :: Zipper a -> a
是comonadic函数,通常称为extract
。
extract = here
因此,可以公平地说每次检查拉链指向的东西时,你都在使用comonadic接口。
那就是说,extract
是界面的无聊一面。更有趣的是extend
。
extend :: (Zipper a -> b) -> Zipper a -> Zipper b
extend
捕获的内容是将“上下文转换”应用于拉链中的每个元素。 Comonadic结构指出,有一种标准且结构良好的方法可以通过“extend
”转换到整个comonad来实现。
这样的例子可能是将卷积应用于列表 - 例如,一点点模糊功能:
blurKernel :: Fractional a => Zipper a -> a
blurKernel (Zipper prior current future) =
(a + current + c) / 3
where
a = case prior of
[] -> 0
(p:ps) -> p
c = case future of
[] -> 0
(p:ps) -> p
blur :: Fractional a => Zipper a -> Zipper a
blur = extend blurKernel
那么为什么要用这些术语写blur
?是否有一种自然的,递归的或迭代的表达方式可以起作用并且更明显?
好吧,通过认识blur
基于comonadic扩展,我们在Zippers操作中暴露了常见的结构。这有利于维持DRY。
我们也开始认识到Zippers的一些深刻内容 - 每个拉链都有comonadic extend
所以我们可以通过某种方式概括blur
来概括Fractional
所有blurKernel
类型的拉链1}}和extend
在我们关心的每个拉链中。
无论如何,我希望我的例子证明Zippers是comonads,无论你是否注意到它。
这通常是好的Haskell抽象的情况 - 它们是关于某些类型的代码运行方式的自然属性。为方便起见,仅键入类捕获它们。 Maybe
/ State
/ List
/等即使不是Monad
,也会是monad。而Zipper
/ Store
/ Trace
即使不是Comonad
也是comonads。