Type-Driven Development with Idris介绍:
twoPlusTwoNotFive : 2 + 2 = 5 -> Void
twoPlusTwoNotFive Refl impossible
以上是功能还是价值?如果它是前者,那么为什么没有变量参数,例如
add1 : Int -> Int
add1 x = x + 1
特别是,我对=
中缺少twoPlusTwoNotFive
感到困惑。
答案 0 :(得分:5)
impossible
调用了很多不可能的参数组合。伊德里斯赦免了在案件不可能的情况下提供右手边的责任。
在这种情况下,我们正在编写(2 + 2 = 5) -> Void
类型的函数。 Void
是一个没有值的类型,所以如果我们成功实现了这样一个函数,我们应该期望它的所有情况都是不可能的。现在,=
只有一个构造函数(Refl : x = x
),它不能在这里使用,因为它要求=
的参数在定义上相等 - 它们有要相同的x
。所以,很自然地,它是impossible
。任何人都无法在运行时成功调用此函数,并且我们不必证明某些事情不是真的,这本来就是一个很大的问题。
这是另一个例子:你不能索引到一个空矢量。仔细检查Vect
并将其发现为[]
告诉我们n ~ Z
;由于Fin n
是自然数小于n
的类型,因此调用者无法用来填充第二个参数。
at : Vect n a -> Fin n -> a
at [] FZ impossible
at [] (FS i) impossible
at (x::xs) FZ = x
at (x::xs) (FS i) = at xs i
大部分时间你都被允许完全省略不可能的案件。
我略微偏爱Agda的相同概念的符号,它使用符号()
明确指出输入表达式的哪一位是不可能的。
twoPlusTwoNotFive : (2 + 2 ≡ 5) -> ⊥
twoPlusTwoNotFive () -- again, no RHS
at : forall {n}{A : Set} -> Vec A n -> Fin n -> A
at [] ()
at (x ∷ xs) zero = x
at (x ∷ xs) (suc i) = at xs i
我喜欢它,因为有时你只是在对参数进行进一步的模式匹配后才知道案例是不可能的;当不可能的东西埋下几层时,有一个视觉辅助可以帮助你找到它的位置。