2014-12-03 95 views
14

为什么当你定义函数复制Comonad复制功能

duplicate :: w a -> w (w a)  

的Comonad类型类(link),你必须修改“的背景下,”所有元素(即更改除当前其他元素值的上下文)。为什么不只是使用类似的东西在Monad中返回

例(拉链):

data Z a = Z [a] a [a]  

,为什么我就不能定义重复的

duplicate z = Z [] z []  

我试图得到要求的从Comonad规则复制功能,但我总最后得到一个重复的东西,就像返回一样,它不需要做任何其他事情。

一个blog post说:

重复是有点难以把握。从列表拉链,我们必须建立列表拉链的列表拉链。这背后的意义(由共同法律证实,每个实例都必须履行)是在复制结构内移动返回原来的结构,由相同的移动改变

但我不明白为什么它必须是那样。该FMAP在Comonad规则始终适用于包装的元素,后来这一个元素总是“展开”与提取,何苦做别的事情在重复其他不仅仅是包装的参数复制功能?

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

在此先感谢您的回复!

+0

你可能会对这个问题感兴趣,这个问题是关于一般为任何可区分类型派生用于拉链的comonad实例的。 http://stackoverflow.com/q/25554062/414413如果是这样,请检查pigworker广泛的解决方案与偏微分方程或我的解决方案与二阶导数。 – Cirdec 2014-12-03 20:43:39

+0

感谢您的链接,当我试图找到我的问题的答案时,我滚动它,但现在当您明确推荐它时,我发现它有大量新东西供我思考。我肯定会研究它。 – Jackie 2014-12-05 09:58:12

回答

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 

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

f =<= g = f . fmap g . duplicate 

这看起来很容易推理。现在,让我们为您的Z类型配备另一个我们可以谈论的功能。 isFirst只有在Z表示一个列表中某个位置上的某个值时才会返回true,前面没有任何值。

isFirst :: Z a -> Bool 
isFirst (Z [] _ _) = True 
isFirst _   = False 

现在,让我们来看看会发生什么,当我们使用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 

当我们尝试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 

当我们duplicate d我们失去了对结构的信息。事实上,除了拉链的单一焦点之外,我们失去了到处传播的所有信息。正确的duplicate在上下文中的每个位置都有一个“拉链”,它在该位置和该位置的上下文中保存该值。

让我们看看我们可以从这些法则中推论出什么。用一个小手挥动功能类别,我们可以看到=<= extractfmap extract . duplicate,这需要是身份函数。显然,我重新发现了如何在Control.Category的文档中编写法律。这让我们写类似

z = (=<= extract)    z 
z = fmap extract . duplicate $ z 

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

Z left x right = fmap extract . duplicate $ Z left x right 

从他们输入重复的,我们知道它必须返回相同的构造。

Z left x right = fmap extract $ Z lefts (Z l x' r) rights 

如果我们将fmap这个Z我们

Z left x right = Z (fmap extract lefts) (extract (Z l x' r)) (fmap extract rights) 

如果我们分手这件事由Z构造的部分,我们有三个方程

left = fmap extract lefts 
x = extract (Z l x' r) 
right = fmap extract rights 

这就告诉我们,至少duplicate (Z left x right)的结果必须成立:

  • 具有相同长度的左侧的列表作为left
  • 在中间x一个Z用于与相同的长度right用于右侧
中间
  • 列表

    此外,我们可以看到左侧和右侧列表中的中间值必须与那些列表中的原始值相同。考虑到这一条法则,我们足够了解duplicate的结果要求不同的结构。

  • +0

    嗨,Cirdec,你钉了它。我试图自己想出一个反例,但我总是瞄准重点,我从来没有试图查询上下文(就像你的'isFirst'那样)。这不仅是正确的答案,而且还包含有关该主题的更多有用信息。 Upvoting和标记为已接受的答案。 – Jackie 2014-12-05 09:53:17