这种类型中使用的agda命题 - 它是什么意思?

时间:2013-08-18 05:55:54

标签: agda dependent-type

我从“残酷的Agda简介”http://oxij.org/note/BrutalDepTypes/

中接受了这一点

假设我们想要在偶数上定义除以2。我们可以这样做:

div : (n : N) -> even n -> N
div zero p = zero
div (succ (succ n)) p= succ (div n p)
div (succ zero) ()

N是自然数,甚至是以下“命题”

even : N -> Set
even zero = \top
even (succ zero) = \bot
even (succ (succ n)) = even n
data \bot : Set where
record \top : Set where

评估表达式时     div(succ(succ zero)) 你得到     \ p - > succ零 这是你所期望的。但是,我不明白的是如何解释\ p。我也不明白代码是什么     f:\ bot - > ñ     f = div(succ zero) 手段。据我所知,\ bot暗示A代表任何A ......所以类型是有效的。我想我认为依赖类型将允许我以这样的方式写div:div(succ zero)将更明确地失败类型检查。

有人可以就如何在agda中使用和查看谓词提出建议吗?

1 个答案:

答案 0 :(得分:8)

您示例中的p证明您要划分的数字(n)确实是even。如果您想使用div功能划分数字,仅提供数字是不够的! Agda通过向您返回另一个函数来表示这一功能 - 这个函数使用2是even的证明并返回1。

让我们写一些测试来看看它是如何工作的:

test₁ : ℕ
test₁ = div 4 ?

在这种情况下,洞的类型是毫无疑问的even 4分两步缩小为,因此您可以轻松填写​​空白记录或仅提供下划线 - 只有一个可能的值,Agda可以填写:

test₁ = div 4 _

另一方面,当你给它一个奇数时,例如:

test₂ : ℕ
test₂ = div 3 ?

洞的类型减少到是空类型;给出这种类型的价值相当于证明你的逻辑中存在矛盾。所以我们被困在这里 - 这正是我们想要的。


现在,你想让它感觉更多......隐含的,当我们试图给它一个奇数时,可能会引入编译错误。

Agda只能通过统一填写隐含的内容。虽然统一可以做一些复杂的事情,但有一些问题无法帮助;猜测证据就是其中之一。如果我们想隐瞒证据,我们必须保持简单。 even就是一个很好的例子:我们可以从我们正在划分的数字中完整地计算它,它可以返回(可以简单填写)或(这意味着有什么不对的。)

div-implicit : (n : ℕ) {p : even n} → ℕ
div-implicit n {p} = div n p

偶数也很好:

test₃ : ℕ
test₃ = div-implicit 4

奇数会产生编译错误,请参阅我的previous answer。我们得到明亮的黄色,我不知道填写错误:

___10 : ⊥  [ at D:\Agda\SO6.agda:27,9-23 ]

这是一本关于如何通过Agda猜测琐碎证明义务的手册:

首先,我们需要一个确定参数是否正常的函数。通常,这是一个返回BoolDec

的函数
check : ℕ → Bool

接下来,我们将Bool转换为命题:

-- The Bool is true.
True : Bool → Set
True true  = ⊤
True false = ⊥

-- The Bool is false.
False : Bool → Set
False true  = ⊥
False false = ⊤

最后,我们可以包含一个隐含的参数,如果参数合适,Agda会填写,或者返回亮黄色:

f : (n : ℕ) {p : True (check n)} → ℕ

如果您发现其中一个参数没有意义,那么Agda允许您省略函数方程的右侧,可以这么说。从技术上讲,当你把一个()写成一个模式时,你断言任何人都无法提供该类型的参数 - 如果没有人能用这些参数实际调用函数,为什么还要写右手边?考虑一个例子:

f : (m n : ℕ) → m ≡ n → ℕ
f zero (suc zero) p = ?
f _ _ _ = ?

p的类型是什么?这是0 ≡ 1的证据 - 这显然是无意义的,没有人可以调用f 0 1并提供0 ≡ 1的证明。我们有理由将p替换为()并忽略右侧:

f zero (suc zero) ()

将此应用于div示例:

div (suc zero) p = ?

现在,p的类型为。任何人都无法提供类型的值。再说一遍,我们告知Agda这个案子是不可能的:

div (suc zero) ()

现在,那些问号是什么?关于agda-mode的好处是它可以帮助您以合作的方式构建程序。当你在某个地方写?时,你会告诉agda-mode“我不知道这里发生了什么,让我们一起找出来。”

当您通过C-c C-l检查文件时,Agda会将?转换为 hole (这些是您看到的{ }0 。你可以在一个程序中有一个以上的洞,这解释了背后的数字。

现在,我说这些允许你以合作的方式建立计划,合作在哪里?你可以通过一些洞来做很多动作。例如,您可以询问其类型(通过C-c C-,):

div : (n : ℕ) → even n → ℕ
div zero          p  = zero
div (suc (suc n)) p  = { }0
div (suc zero)    ()

-- Agda information buffer
Goal: ℕ
————————————————————————————————————————————————————————————
p : even n
n : ℕ

这三行告诉您,您最终必须写下类型的目标(目标),并且在范围p even nn范围内类型为

你甚至可以在洞内写东西,询问你目前写的是什么类型(通过C-c C-.):

div (suc (suc n)) p = {n }0

-- Agda information buffer
Goal: ℕ
Have: ℕ
————————————————————————————————————————————————————————————
p : even n
n : ℕ

当你满意的时候,你可以通过C-c C-space用你在里面写的任何东西(好吧,只要它的类型)来替换这个洞。

如果你不关心实现(例如,你正在编写证据而且会做任何事情),你也可以告诉Agda尝试通过C-c C-a来猜测它。当你有很多琐碎的案例时,这非常有用。

然后是案件分裂。编写函数时,通常需要进行模式匹配以了解有关参数的更多信息。 Agda允许您节省手动编写所有这些函数方程式的一些痛苦。

_+_ : (m n : ℕ) → ℕ
m + n = { }0

我们写一个变量,我们想要在洞内分割一个案例:

_+_ : (m n : ℕ) → ℕ
m + n = {m }0

然后按下神奇的C-c C-c并瞧瞧:

_+_ : (m n : ℕ) → ℕ
zero + n = { }0
suc m + n = { }1