首页 文章

一个不平凡的共生体是什么样的?

提问于
浏览
31

例如,在Haskell的_3044004中提到了类共同体:

由于Haskell中缺少非平凡的共生,我们可以限制自己需要一个Functor而不是一些Coapplicative类 .

经过一番搜索后,我找到了一个StackOverflow answer,用共同必须满足的法则解释了这一点 . 所以我想我理解为什么在Haskell中假设的Comonoid类型类只有一个可能的实例 .

因此,为了找到一个不平凡的共生体,我想我们必须寻找其他类别 . 当然,如果类别理论家有共同体的名称,那么有一些有趣的 . 该页面上的其他答案似乎暗示了一个涉及 Supply 的例子,但我无法弄明白仍然满足法律 .

我也转向维基百科:有参考类别理论,这在我看来是Haskell的 Monoid 类型类的充分描述,但是"comonoid"重定向到一个类别理论描述的幺半群和共生组合,我可以't understand, and there still don'似乎是任何有趣的例子 .

所以我的问题是:

  • comonoids可以用非类别理论术语解释,比如幺半群吗?

  • 有趣的comonoid的一个简单例子是什么,即使它不是Haskell类型? (可以通过熟悉的Haskell monad在Kleisli类别中找到一个吗?)

edit: 我不确定这实际上是否在类别理论上是正确的,但我在问题2的括号中想象的是 delete :: a -> m ()split :: a -> m (a, a) 的一些特定Haskell类型 a 和Haskell monad m 的非平凡定义,它们满足Kleisli-arrow版本的联想答案中的共同法则 . 其他共生体的例子仍然受到欢迎 .

3 回答

  • 1

    正如Phillip JF所提到的,comonoids在子结构逻辑中很有趣 . 我们来谈谈线性lambda演算 . 这非常类似于普通类型的lambda演算,除了每个变量必须只使用一次 .

    为了感受一下,让我们count linear functions of given types,即

    a -> a
    

    只有一个居民, id . 而

    (a,a) -> (a,a)
    

    有两个, idflip . 请注意,在常规的lambda演算 (a,a) -> (a,a) 中有四个居民

    (a, b) ↦ (a, a)
    (a, b) ↦ (b, b)
    (a, b) ↦ (a, b)
    (a, b) ↦ (b, a)
    

    但前两个要求我们使用其中一个参数而丢弃另一个 . 这正是线性lambda演算的本质 - 不允许这些函数 .


    简而言之,线性液晶显示器有什么意义?好吧,我们可以用它来模拟线性效应或资源使用 . 例如,如果我们有一个文件类型和一些变形金刚,它可能看起来像

    data File
    open  :: String -> File
    close :: File   -> ()      -- consumes a file, but we're ignoring purity right now
    t1    :: File -> File
    t2    :: File -> File
    

    然后以下是有效的管道:

    close . t1 . t2 . open
    close . t2 . t1 . open
    close . t1      . open
    close . t2      . open
    

    但这种“分支”计算不是

    let f1 = open "foo"
        f2 = t1 f1
        f3 = t2 f1
    in close f3
    

    因为我们两次使用 f1 .


    现在,您可能想知道关于线性规则必须遵循的内容 . 例如,我决定某些管道不必同时包含 t1t2 (比较之前的枚举练习) . 此外,我介绍了 openclose 函数,尽管这些函数违反了线性,但它们很乐意创建并销毁 File 类型 .

    实际上,我们可能认为存在违反线性的函数 - 但并非所有客户都可能 . 它就像 IO monad一样 - 所有的秘密都存在于 IO 的实现中,以便用户在"pure"世界中工作 .

    这就是 Comonoid 的用武之地 .

    class Comonoid m where
      destroy :: m -> ()
      split   :: m -> (m, m)
    

    在线性lambda演算中实例化 Comonoid 的类型是具有随身破坏和复制规则的类型 . 换句话说,它完全受到线性lambda演算的约束 .

    由于Haskell根本没有实现线性lambda演算规则,我们总是可以实例化 Comonoid

    instance Comonoid a where
      destroy a = ()
      split a   = (a, a)
    

    或者,也许另一种思考方式是Haskell是一个线性LC系统,只是碰巧为每种类型实例化 Comonoid 并自动应用 destroysplit .

  • 42
    • 通常意义上的幺半群与集合类别中的分类幺半群相同 . 人们可以预期,通常意义上的共生体与集合类别中的分类共生体相同 . 但是集合类别中的每个集合都是一个微不足道的共生体,所以显然没有类别的非类别描述与幺半群的平行 .

    • 只是像monad是endofunctors类别中的monoid(什么's the problem?), a comonad is a comonoid in the category of endofunctors (what'是coproblem?)所以是的,Haskell中的任何comonad都是comonoid的一个例子 .

  • 17

    那么我们可以想到一个monoid的方式就像我们正在使用的任何特定产品结构一样,所以在Set中我们会采用这个签名:

    mul : A * A -> A
    one : A
    

    到这一个:

    dup : A -> A * A
    one : A
    

    但是二元性的概念是,你可以制作的逻辑语句都具有可以应用于双重对象的对偶,并且还有另一种方式来说明幺半群是什么,并且这与产品构造的选择无关,然后当我们采用结构时,我们可以在输出中获取副产品,例如:

    div : A -> A + A
    one : A
    

    哪里是标记的总和 . 在这里,我们基本上已经知道这个类型中的每个单词总是准备好 produce 一个新位,它隐含地来自用于表示A的左侧或右侧实例的标签 . 我个人认为这真的很酷 . 我认为人们在上面讨论的事情的酷版本是当你没有特别为幺半群构建时,而是为了幺半群行动 .

    如果有一个函数,则认为幺半群M作用于集合A.

    act : M * A -> A
    

    我们有以下规则

    act identity a = a
    act f (act g a) = act (f * g) a
    

    如果我们想要一个共同行动,我们到底想要什么?

    act : A -> M * A
    

    这会让我们产生一种类型的comonoid!我在为这些系统制定法律方面遇到了很多麻烦,但我认为它们必须在某个地方,所以我今晚要继续寻找 . 如果有人可以告诉我他们或者我以某种方式对这些事情做错了,也对此感兴趣 .

相关问题