Haskell 一个普通的科摩罗看起来像什么?
例如,在哈斯克尔的著作中提到了科摩罗类: 由于Haskell中缺少非平凡的comonoids,我们可以限制自己只需要一个函子而不是一些协同应用类 经过一点搜索,我发现了一个更能解释这一点的方法,即科摩罗类动物必须满足的法则。所以我想我理解为什么在Haskell中只有一个假设的Comonoid类型类的实例 因此,为了找到一种非平凡的科摩罗类,我想我们必须寻找其他类别。当然,如果范畴理论家对科莫类有一个名字,那么还有一些有趣的名字。该页上的其他答案似乎暗示了一个涉及Haskell 一个普通的科摩罗看起来像什么?,haskell,category-theory,Haskell,Category Theory,例如,在哈斯克尔的著作中提到了科摩罗类: 由于Haskell中缺少非平凡的comonoids,我们可以限制自己只需要一个函子而不是一些协同应用类 经过一点搜索,我发现了一个更能解释这一点的方法,即科摩罗类动物必须满足的法则。所以我想我理解为什么在Haskell中只有一个假设的Comonoid类型类的实例 因此,为了找到一种非平凡的科摩罗类,我想我们必须寻找其他类别。当然,如果范畴理论家对科莫类有一个名字,那么还有一些有趣的名字。该页上的其他答案似乎暗示了一个涉及供应的例子,但我无法找出一个仍然符
供应的例子,但我无法找出一个仍然符合法律的例子
我还转向了维基百科:有一个关于monoids的页面没有引用范畴理论,在我看来,这是对Haskell的Monoid
typeclass的充分描述,但“comonoid”重定向到了一个范畴理论描述,我无法理解monoids和comonoids在一起,而且似乎仍然没有任何有趣的例子
因此,我的问题是:
可以用非范畴理论的术语如幺半群来解释吗
哪一个简单的例子是有趣的科莫类动物,即使它不是Haskell类型?(在一个熟悉的哈斯凯尔·蒙纳德(Haskell monad)之上,能找到一个克莱斯利分类吗?)
编辑:我不确定这在理论上是否正确,但我在问题2的括号中想象的是delete::a->m()
和split::a->m(a,a)的非平凡定义
针对某些特定的Haskell类型a
和Haskell monadm
,这些类型满足链接答案中科摩罗定律的Kleisli-arrow版本。科摩罗类的其他例子仍然受欢迎
通常意义上的幺半群与集合范畴中的范畴幺半群相同。人们会认为,通常意义上的科摩罗类与集合范畴中的分类科摩罗类是相同的。但集合范畴中的每一个集合都是一个平凡的共形,因此显然,并没有与幺半群平行的共形的非范畴描述
就像单子是内函子范畴中的幺半群一样(问题是什么?),余子是内函子范畴中的余子(共问题是什么?),所以是的,Haskell中的任何余子都是余子的一个例子
正如Phillip JF所提到的,在子结构逻辑中讨论comonoids是很有趣的。让我们来谈谈线性lambda演算。这与普通类型的lambda演算非常相似,只是每个变量必须只使用一次
为了得到一种感觉,让我们
只有一个居民,id
。当
(a,a) -> (a,a)
有两个,id
和flip
。注意,在正则lambda演算中(a,a)->(a,a)
有四个居民
(a, b) ↦ (a, a)
(a, b) ↦ (b, b)
(a, b) ↦ (a, b)
(a, b) ↦ (b, a)
但前两个要求我们使用其中一个参数两次,同时丢弃另一个参数。这正是线性lambda演算的本质,它不允许这些函数
顺便提一下,线性LC有什么意义?我们可以用它来模拟线性效应或资源使用。例如,如果我们有一个文件类型和一些转换器,它可能看起来像
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
两次
现在,你可能想知道什么东西必须遵循线性规则。例如,我决定一些管道不必同时包含t1
和t2
(比较前面的枚举练习)。此外,我还引入了open
和close
函数,它们可以愉快地创建和销毁文件
类型,尽管这违反了线性
事实上,我们可以假设存在违反线性的函数,但并非所有的客户都可以。这很像IO
monad,所有的秘密都存在于IO
的实现中,因此用户在一个“纯粹”的世界中工作
这就是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
,并为您自动应用destroy
和split
。我们可以想到的一种方法是将幺半群与我们正在使用的任何特定产品结构挂钩,因此,在集合中,我们将采用以下签名:
mul : A * A -> A
one : A
对于这一点:
dup : A -> A * A
one : A
但是二元性的概念是,你可以做出的逻辑陈述都有二元性,可以应用于二元对象,还有另一种方式来说明幺半群是什么,这与产品结构的选择无关,然后当我们取结构时,我们可以在输出中取副产品,比如:
div : A -> A + A
one : A
其中+是标记的和。在这里,我们基本上知道,这种类型的每一个术语总是准备产生一个新的位,它隐式地来自于用于表示a的左或右实例的标记。我个人认为这真是太酷了。我认为人们在上面讨论的事情的一个很酷的版本是,当你不是特别为幺半群构造它,而是为幺半群动作
若有函数,则称幺半群M作用于集合A
act : M * A -> A
在哪里
act : M * A -> A
act identity a = a
act f (act g a) = act (f * g) a
act : A -> M * A