我在伊德里斯尝试过这个。虽然我同意 pigworker 重新制定问题的建议,但您必须这样做才能使您的定义通过 Idris 类型检查器。首先,单例 Nats:
data SNat : Nat -> Set where
ZZ : SNat O
SS : SNat k -> SNat (S k)
然后,区间的定义:
data Interval : Nat -> Nat -> Set where
Go : Interval m n -> Interval m (S n)
Empty : SNat n -> Interval n n
您想要的 intervalLength 定义看起来有点像这样:
intervalLength : Interval n (plus len n) -> SNat len
intervalLength (Empty sn) = ZZ
intervalLength (Go i) = SS (intervalLength i)
但是你会遇到麻烦,因为正如你所说plus
的不是单射的。我们可以通过len
显式地进行额外的模式匹配来到达某个地方——然后统一可以取得一些进展:
intervalLength : Interval n (plus len n) -> SNat len
intervalLength {len = O} (Empty sn) = ZZ
intervalLength {len = S k} (Go i) = SS (intervalLength i)
这很好,并且通过了类型检查器,但不幸的是它不相信该功能是完整的:
*interval> :total intervalLength
not total as there are missing cases
缺少的案例是这个:
intervalLength {len = O} (Go i) = ?missing
如果你尝试这个,并询问 REPL 的类型missing
,你会看到:
missing : (n : Nat) -> (i : Interval (S n) n) -> SNat O
现在,我们知道类型Interval (S n) n
是空的,但是类型检查器却没有。不知何故我们需要写badInterval : Interval (S n) n -> _|_
,然后我们可以说:
intervalLength {len = O} (Go i) = FalseElim (badInterval i)
我将把定义badInterval
作为练习:-)。这不是特别棘手,但不得不这样做有点无聊 - 有时很难避免不得不使用这种类型的类型,但实施badInterval
支持 pigworker 不这样做的建议!