我正在使用这种类型来推断可以执行可判定解析的字符串:
data Every : (a -> Type) -> List a -> Type where
Nil : {P : a -> Type} -> Every P []
(::) : {P : a -> Type} -> P x -> Every P xs -> Every P (x::xs)
例如,像这样定义数字 [0-9]:
data Digit : Char -> Type where
Zero : Digit '0'
One : Digit '1'
Two : Digit '2'
Three : Digit '3'
Four : Digit '4'
Five : Digit '5'
Six : Digit '6'
Seven : Digit '7'
Eight : Digit '8'
Nine : Digit '9'
digitToNat : Digit a -> Nat
digitToNat Zero = 0
digitToNat One = 1
digitToNat Two = 2
digitToNat Three = 3
digitToNat Four = 4
digitToNat Five = 5
digitToNat Six = 6
digitToNat Seven = 7
digitToNat Eight = 8
digitToNat Nine = 9
那么我们可以有以下功能:
fromDigits : Every Digit xs -> Nat -> Nat
fromDigits [] k = 0
fromDigits (x :: xs) k = (digitToNat x) * (pow 10 k) + fromDigits xs (k-1)
s2n : (s : String) -> {auto p : Every Digit (unpack s)} -> Nat
s2n {p} s = fromDigits p (length s - 1)
这个s2n
函数现在可以在编译时正常工作,但它本身并不是很有用。要在运行时使用它,我们必须先构造证明Every Digit (unpack s)
,然后才能使用该函数。
所以我想我现在想写这样的函数:
every : (p : a -> Type) -> (xs : List a) -> Maybe $ Every p xs
或者我们想要返回成员资格证明或非成员资格证明,但我不完全确定如何以一般方式执行这些操作。因此,我尝试Maybe
只为字符制作版本:
every : (p : Char -> Type) -> (xs : List Char) -> Maybe $ Every p xs
every p [] = Just []
every p (x :: xs) with (decEq x '0')
every p ('0' :: xs) | (Yes Refl) = Just $ p '0' :: !(every p xs)
every p (x :: xs) | (No contra) = Nothing
但后来我得到这个统一错误:
Can't unify
Type
with
p '0'
Specifically:
Can't unify
Type
with
p '0'
但p
属于类型Char -> Type
。我不确定是什么导致了这个统一失败,但认为这个问题可能与我之前的问题有关。
这是我想要做的事情的明智方法吗?我觉得目前的工作有点多,这些功能的更通用版本应该是可能的。auto
如果关键字可以用于编写一个函数给你一个Maybe proof
或一个,这将是很好的Either proof proofThatItIsNot
,就像DecEq
类的工作方式一样。