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