Comonad重复功能

Jac*_*kie 14 haskell comonad

为什么在定义函数重复时

   duplicate :: w a -> w (w a)     
Run Code Online (Sandbox Code Playgroud)

对于Comonad类型类(链接),您必须修改"在上下文中"的所有元素(即更改除上下文当前值之外的元素).为什么不在Monad中使用像返回这样的东西?

示例(拉链):

   data Z a = Z [a] a [a]     
Run Code Online (Sandbox Code Playgroud)

为什么我不能将副本定义为

   duplicate z = Z [] z []     
Run Code Online (Sandbox Code Playgroud)

我试图从Comonad规则中获得重复函数的要求,但我总是得到一个副本,它只是将元素包装成monad中的返回而不需要做任何其他操作.

一篇博文说:

复制有点难以掌握.从列表拉链中,我们必须构建列表拉链的列表拉链.这背后的意义(由每个实例必须履行的comonad法律确认)是在复制结构内部移动返回原始结构,由同一移动改变

但我不明白为什么一定是那样.该FMAP在Comonad规则始终适用于包装的元素,后来这一个元素总是"展开"与提取物,为什么还要做别的事情在重复的功能不仅仅是包装的论点其他复制

你能指出我错过了什么吗?我觉得我在某个地方犯了一些明显的错误,但我无法自己搞清楚.

在此先感谢您的回复!

Cir*_*dec 6

重要的是,如果你可以做类型的其他事情,而不仅仅是extract从它.直观地说,如果你唯一可以做的就是提取值,那么类型只保存一个值,所以重复那个值就是复制一切.一般情况下并非如此,拉链并非如此.

Comonad法律是公正的法律类变相的类型的功能w a -> b.由于这些来自类别,因此在类别方面而不是在Comonad法律方面可能更容易推理它们. extract是此类别的标识, =<=是组合运算符.

-- | Right-to-left 'Cokleisli' composition
(=<=) :: Comonad w => (w b -> c) -> (w a -> b) -> w a -> c
f =<= g = f . extend g
Run Code Online (Sandbox Code Playgroud)

我们也知道extend f = fmap f . duplicate,所以我们可以写

f =<= g = f . fmap g . duplicate
Run Code Online (Sandbox Code Playgroud)

这看起来很容易理解.现在,让我们为您的Z类型装备我们可以谈论的另一个功能.isFirst仅当Z表示列表中某个位置的值时才返回true .

isFirst :: Z a -> Bool
isFirst (Z [] _ _) = True
isFirst  _         = False
Run Code Online (Sandbox Code Playgroud)

现在,让我们考虑当我们使用isFirst三类法则时会发生什么.似乎只有两个可以立即适用于它是extract组合的左右身份=<=.由于我们只反驳这一点,我们只需要找到一个反例.我怀疑其中一个extract =<= isFirstisFirst =<= extract将失败的输入Z [1] 2 [].这两者应该是相同的isFirst $ Z [1] 2 [],即False.我们会extract =<= isFirst先尝试,这恰好可以解决.

extract  =<=   isFirst               $  Z [1] 2 []
extract . fmap isFirst . duplicate   $  Z [1] 2 []
extract . fmap isFirst $ Z []          (Z [1] 2 [])  []
extract                $ Z [] (isFirst (Z [1] 2 [])) []
extract                $ Z []  False                 []
                               False
Run Code Online (Sandbox Code Playgroud)

当我们尝试时,isFirst =<= extract我们不会那么幸运.

isFirst  =<=   extract               $  Z [1] 2 []
isFirst . fmap extract . duplicate   $  Z [1] 2 []
isFirst . fmap extract $ Z []          (Z [1] 2 [])  []
isFirst                $ Z [] (extract (Z [1] 2 [])) []
isFirst                $ Z []  2                     []
True
Run Code Online (Sandbox Code Playgroud)

当我们duplicate失去有关结构的信息时.实际上,除了拉链的单个焦点外,我们丢失了有关到处传播的所有内容的信息.正确的duplicate将在上下文中的任何地方都有一个完整的"拉链"拉链,其中包含该位置的值和该位置​​的上下文.

让我们看看我们可以从这些法律中推断出什么.随着一点点的手舞动的功能范畴,我们可以看到,=<= extract就是fmap extract . duplicate,这需要有身份的功能.显然我正在重新发现法律是如何写在文档中的Control.Category.这让我们写出类似的东西

z = (=<= extract)              z
z = fmap extract . duplicate $ z
Run Code Online (Sandbox Code Playgroud)

现在,z只有一个构造函数,所以我们可以替换它

Z left x right = fmap extract . duplicate $ Z left x right
Run Code Online (Sandbox Code Playgroud)

从他们的重复类型,我们知道它必须返回相同的构造函数.

Z left x right = fmap extract $ Z lefts (Z l x' r) rights
Run Code Online (Sandbox Code Playgroud)

如果我们申请fmap这个,Z我们有

Z left x right = Z (fmap extract lefts) (extract (Z l x' r)) (fmap extract rights)
Run Code Online (Sandbox Code Playgroud)

如果我们通过Z构造函数的部分将其拆分,我们有三个方程式

left = fmap extract lefts
x = extract (Z l x' r)
right = fmap extract rights
Run Code Online (Sandbox Code Playgroud)

这告诉我们至少duplicate (Z left x right)必须保持的结果:

  • left左侧长度相同的列表
  • 一个Zx中间为中间
  • right右侧长度相同的列表

此外,我们可以看到左侧和右侧列表中的中间值必须与这些列表中的原始值相同.考虑到这一个法律,我们知道足够的要求结果的不同结构duplicate.