Syntax 理解Agda的语法
以下面的例子为例Syntax 理解Agda的语法,syntax,agda,Syntax,Agda,以下面的例子为例 postulate DNE : {A : Set} → ¬ (¬ A) → A data ∨ (A B : Set) : Set where inl : A → A ∨ B inr : B → A ∨ B -- Use double negation to prove exclude middle classical-2 : {A : Set} → A ∨ ¬ A classical-2 = λ {A} → DNE (λ z → z (inr (λ x → z (
postulate DNE : {A : Set} → ¬ (¬ A) → A
data ∨ (A B : Set) : Set where
inl : A → A ∨ B
inr : B → A ∨ B
-- Use double negation to prove exclude middle
classical-2 : {A : Set} → A ∨ ¬ A
classical-2 = λ {A} → DNE (λ z → z (inr (λ x → z (inl x)))
我知道这是正确的,纯粹是因为agda是如何工作的,但我对这种语言不熟悉,无法理解它的语法是如何工作的,如果有人能告诉我发生了什么,我将不胜感激,谢谢:)
我在haskell有经验,虽然那是大约一年前的事了。让我们从假设开始。语法很简单:
postulate name : type
这断言存在称为name
的类型type
的某些值。将其视为逻辑中的公理——被定义为真实且不受质疑的事物(在本例中为Agda)
接下来是数据定义。mixfix声明有一点疏忽,所以我将修复它并解释它的作用。第一行:
data _∨_ (A B : Set) : Set where
引入一个名为_∨_代码><代码>_∨_
接受两个类型为Set
的参数,然后返回一个Set
我会把它和哈斯克尔比较。A
和B
在以下示例中或多或少等同于A
和B
:
data Or a b = Inl a | Inr b
这意味着数据定义定义了多态类型(模板或泛型,如果愿意)Set
是Agda与Haskell的*
的等价物
下划线是怎么回事?Agda允许您定义任意运算符(前缀、后缀、中缀…通常仅由一个名称-mixfix调用)。下划线只是告诉Agda参数在哪里。这在前缀/后缀运算符中最为明显:
-_ : Integer → Integer -- unary minus
- n = 0 - n
_++ : Integer → Integer -- postfix increment
x ++ = x + 1
您甚至可以创建疯狂的运算符,例如:
if_then_else_ : ...
下一部分是数据构造函数本身的定义。如果你看过Haskell的GADTs,这或多或少是一样的。如果您没有: 当您在Haskell中定义构造函数时,比如上面的
Inr
,您只需指定参数的类型,Haskell就会计算出整个事件的类型,即Inr::b->或a b
。当您在Agda中编写GADT或定义数据类型时,需要指定整个类型(这有很好的理由,但我现在不深入讨论)
因此,数据定义指定了两个构造函数,inl
,类型为A→ A.∨ B和inr
类型的B→ A.∨ B
现在是有趣的部分:classic-2
的第一行是一个简单的类型声明。Set
是怎么回事?在Haskell中编写多态函数时,只需使用小写字母表示类型变量,例如:
id :: a -> a
你真正的意思是:
id :: forall a. a -> a
你真正的意思是:
id :: forall a. a -> a
也就是说,它不仅仅是任何一种a
,而是a
是一种类型。Agda让您执行这个额外的步骤,并显式地声明这个量化(这是因为您可以量化更多的东西,而不仅仅是类型)
那卷曲的大括号呢?让我再次使用上面的Haskell示例。当您在某处使用id
函数时,比如说id5
,您不需要指定a=Integer
如果使用普通参数,则每次调用classic-2
时都必须提供实际类型A
。但是,大多数情况下,可以从上下文推断类型(与上面的ID5
示例非常相似),因此对于这些情况,可以“隐藏”参数。Agda然后尝试自动填写,如果不能,它会抱怨
最后一行:λx→ y
是Agda的说法\x->y
。这应该可以解释这条线的大部分,唯一剩下的就是大括号了。我很确定你可以在这里省略它们,但不管怎样:隐藏的参数会按照它们说的做——它们隐藏。因此,当您定义从{a}
到B
的函数时,只需提供B
类型的内容(因为{a}
是隐藏的)。在某些情况下,您需要知道隐藏参数的值,这就是这种特殊的lambda所做的:λ{A}→代码>允许您访问隐藏的A 让我们从假设开始。语法很简单:
postulate name : type
这断言存在称为name
的类型type
的某些值。将其视为逻辑中的公理——被定义为真实且不受质疑的事物(在本例中为Agda)
接下来是数据定义。mixfix声明有一点疏忽,所以我将修复它并解释它的作用。第一行:
data _∨_ (A B : Set) : Set where
引入一个名为_∨_代码><代码>_∨_
接受两个类型为Set
的参数,然后返回一个Set
我会把它和哈斯克尔比较。A
和B
在以下示例中或多或少等同于A
和B
:
data Or a b = Inl a | Inr b
这意味着数据定义定义了多态类型(模板或泛型,如果愿意)Set
是Agda与Haskell的*
的等价物
下划线是怎么回事?Agda允许您定义任意运算符(前缀、后缀、中缀…通常仅由一个名称-mixfix调用)。下划线只是告诉Agda参数在哪里。这在前缀/后缀运算符中最为明显:
-_ : Integer → Integer -- unary minus
- n = 0 - n
_++ : Integer → Integer -- postfix increment
x ++ = x + 1
您甚至可以创建疯狂的运算符,例如:
if_then_else_ : ...
下一部分是数据构造函数本身的定义。如果你看过Haskell的GADTs,这或多或少是一样的。如果您没有:
当您在Haskell中定义构造函数时,比如上面的Inr
,您只需指定参数的类型,Haskell就会计算出整个事件的类型,即Inr::b->或a b
。当您在Agda中编写GADT或定义数据类型时,需要指定整个类型(这有很好的理由,但我现在不深入讨论)
因此,数据定义指定了两个构造函数,inl