我是一位从事类别理论工作的数学家,并且我已经使用Haskell进行了一段时间的计算等工作,但是我绝对不是程序员。我真的很喜欢Haskell,并且希望变得更加流利,而在编写程序时,我发现类型系统是非常有用的。
但是,我最近一直在尝试实现类别理论的东西,并且遇到了一个问题,即您似乎在Haskell中没有类方法法则。如果我的术语是错误的,我的意思是我可以写
class Monoid c where
id :: c -> c
m :: c -> c -> c
但是我不能写一些定律
m (m x y) z == m x $ m y z
根据我的收集,这是由于Haskell中缺少依赖类型,但是我不确定情况到底是什么(现在已经阅读了一些有关依赖类型的信息)。似乎惯例也只是在评论中包括这样的法律,并希望您不要偶然制作一些令其不满意的实例。
DataKinds
之类的扩展名);我是否应该大刀阔斧地转而使用Idris之类的东西;还是对改变我使用Haskell的思维方式的最佳回应(即接受这些法律不能以Haskelly的方式实施)?答案 0 :(得分:7)
[请注意,堆栈溢出不支持mathjax,但是您似乎已经完成了数学学位,所以我假设您可以阅读它]
您要这样:
m (m x y) z = m x (m y z) -- (1)
但是要要求这样做,您需要一种检查方法。因此,您或您的编译器(或证明助手)需要构造此证明。问题是(1)的证明是什么类型?
一个人可以想象一些Proof
类型,但是也许您可以构造一个证明0 = 0
而不是(1)证明,并且两者都具有类型Proof
。因此,您需要一个更通用的类型。我无法决定如何分解其余问题,因此我将对Curry-Howard同构进行简要说明,然后说明如何证明两件事相等,然后说明依存类型如何相关。
Curry-Howard同构说,命题与类型同构,证明与程序同构:类型对应于一个命题,该命题的证明对应于构造一个居住该类型的值的程序。忽略将多少类型表示为类型,一个例子是类型A * B
(在Haskell中写为(A, B)
)对应于命题“ A
和B
”,而类型A + B
(在Haskell中写为Either A B
)对应于命题“ A
或B
”。最后,类型A -> B
对应于“ {{1} }暗示A
,”作为对此的证明,是一个程序收集了B
的证据并为您提供了A
的证据。应该注意的是,没有一种表达B
的方法,但是可以想象添加一个类型为not A
的内置Not A
的类型Either a (Not a)
来排除中间律和{{ 1}}和Not (Not a) -> a
(其中a * Not a -> Void
是一种无法居住的类型,因此对应于false),但是这样一来,您就无法真正运行这些程序来获取构造主义证明。
现在,我们将忽略Haskell的某些现实情况,并想象没有办法绕过这些规则(特别是Void
表示一切都是真实的,undefined :: a
则表示任何事物都暗示着其他任何事物,或者仅仅是其他在其存在并不暗示相应证据的地方不返回的函数。
所以我们知道如何组合命题,但是命题可能是什么?好吧,可以说两种类型是相等的。在Haskell中,这对应于GADT
unsafeCoerce :: a -> b
此构造函数对应于相等的反射性属性。
[旁注:如果到目前为止您仍然很感兴趣,那么您可能有兴趣查找Voevodsky的单价基础,具体取决于您对“同型类型理论”的想法是否感兴趣]
那么我们现在可以证明一些东西吗?平等的传递性如何?
data Eq a b where Refl :: Eq c c
感觉好像还没有真正证明任何东西(特别是因为这主要取决于编译器知道传递和对称属性),但是在证明逻辑上的简单事物时也会有类似的感觉。
那么现在您如何证明原始命题(1)?好吧,让我们想象一下,我们希望类型trans :: Eq a b -> Eq b c -> Eq a c
trans x y =
case x of
Refl -> -- by this match being successful, the compiler now knows that a = b
case y of
Refl -> -- and now b = c and so the compiler knows a = c
Refl -- the compiler knows that this is of type Eq d d, and as it knows a = c, this typechecks as Eq a c
是一个类半群,然后我们还应该证明$ \ forall x,y,z:c,m(mxy)z = mx(myz)。$因此,我们需要一种方法将c
表示为一种类型。严格来说,这不是依赖类型(可以使用m (m x y) z
来提升值和类型族而不是函数)。但是您确实需要依赖类型,以使类型依赖于值。具体来说,如果您具有自然数类型DataKinds
和类型族Nat
(Vec :: Nat -> *
是所有类型的类型(读取类型))固定长度向量,则可以定义一个从属变量类型函数*
。观察输出的类型如何取决于输入的 value 。
因此,您的法律需要将功能提升到类型级别(跳过有关如何定义类型相等和值相等的问题),以及从属类型(组成语法):
mkVec :: (n::Nat) -> Vec n
观察从属类型和证明类型如何趋于庞大。在缺少类型类的语言中,可以将这样的值放入记录中。
关于依赖类型理论的最后注释以及它们如何与咖喱霍华德同构相关。
从属类型可以被认为是一个问题的答案:哪些类型对应于命题$ \ forall x \在S \ quad P(x)$中并且$ \在y \ T \ quad Q(y)中存在?
答案是,您创建了创建类型的新方法:依存积和依存和(coproduct)。从属产品表示“对于$ S类型的所有值$ x $,$都有$ P(x)类型的值。$”正常产品将是$ S = 2的从属产品,$两个值。从属产品可能会写为class Monoid c where
e :: c
(*) :: c -> c -> c
idl :: (x::c) -> Eq x (e * x)
idr :: (x::c) -> Eq x (x * e)
assoc :: (x::c) -> (y::c) -> (z::c) -> Eq ((x * y) * z) (x * (y * z))
。一个相关的和表示“某些类型为$ T $的值$ y $,与类型为$ Q(y)。$的值配对”,可以写成(x:T) -> P x
。
人们可以将它们视为从Set到一般类别的任意索引(联)产品的一般化,在其中可以明智地编写例如$ \ prod_ \ Lambda X(\ lambda),$,有时在类型理论中使用这种表示法。