如何使用Idris构建一个函数,给定一个字符串,返回一个证明这样的字符串是十六进制的(即0x
后面跟2*N
0-9
个字符{ {1}},例如a-f
)?
首先,我为十六进制字符构建了以下类型:
"0x1a7f33b8"
以下类型为十六进制字符串:
data IsNib : Char -> Type where
IsNib0 : IsNib '0'
IsNib1 : IsNib '1'
IsNib2 : IsNib '2'
IsNib3 : IsNib '3'
IsNib4 : IsNib '4'
IsNib5 : IsNib '5'
IsNib6 : IsNib '6'
IsNib7 : IsNib '7'
IsNib8 : IsNib '8'
IsNib9 : IsNib '9'
IsNibA : IsNib 'a'
IsNibB : IsNib 'b'
IsNibC : IsNib 'c'
IsNibD : IsNib 'd'
IsNibE : IsNib 'e'
IsNibF : IsNib 'f'
现在我可以手动构建一个字符串是十六进制的证据:
data IsHex : String -> Type where
IsHexNil : IsHex "0x"
IsHexApp : IsHex s -> IsNib c0 -> IsNib c1 -> IsHex (s ++ singleton c0 ++ singleton c1)
酷!那么,那个为我建立证明的函数呢?这有以下类型:
a : IsHex "0x12"
a = IsHexApp IsHexNil (IsNib '1') (IsNib '2')
这个想法是通过证明字符串上的所有字符都是十六进制来实现它。为此,我需要:
isItHex : (s : String) -> Dec (IsHex s)
这里我遇到了第一个问题。如何证明所有不是isItNib : (c : Char) -> Dec (IsNib c)
isItNib '0' = Yes IsNib0
isItNib '1' = Yes IsNib1
isItNib '2' = Yes IsNib2
isItNib '3' = Yes IsNib3
isItNib '4' = Yes IsNib4
isItNib '5' = Yes IsNib5
isItNib '6' = Yes IsNib6
isItNib '7' = Yes IsNib7
isItNib '8' = Yes IsNib8
isItNib '9' = Yes IsNib9
isItNib 'a' = Yes IsNibA
isItNib 'b' = Yes IsNibB
isItNib 'c' = Yes IsNibC
isItNib 'd' = Yes IsNibD
isItNib 'e' = Yes IsNibE
isItNib 'f' = Yes IsNibF
isItNib a = ?nowWhat
和0-9
的字符都不是十六进制?当然,我可以一个接一个地做到这一点:
a-f
但即便证明这种情况有点复杂。我可以通过证明isItNib 'g' = No ?gIsntHex
无人居住来做到这一点:
IsNib 'g'
然后用以下内容完成:
implementation Uninhabited (IsNib 'g') where
uninhabited IsNib0 impossible
uninhabited IsNib1 impossible
uninhabited IsNib2 impossible
uninhabited IsNib3 impossible
uninhabited IsNib4 impossible
uninhabited IsNib5 impossible
uninhabited IsNib6 impossible
uninhabited IsNib7 impossible
uninhabited IsNib8 impossible
uninhabited IsNib9 impossible
uninhabited IsNibA impossible
uninhabited IsNibB impossible
uninhabited IsNibC impossible
uninhabited IsNibD impossible
uninhabited IsNibE impossible
uninhabited IsNibF impossible
但这18行代码证明单个字符不是十六进制。完成该功能将需要数千行代码。但是,假设我已成功实现它(我可以使用isItNib 'g' = No absurd
作弊)。 assert_unreachable
怎么样?
isItHex
要完成第一个案例,我需要证明:
isItHex : (s : String) -> Dec (IsHex s)
isItHex s with (strList s)
isItHex "" | SNil = ?isItHex_rhs_1
isItHex (strCons x xs) | (SCons x rec) = ?isItHex_rhs_2
对于第二种情况,我需要证明:
--------------------------------------
isItHex_rhs_1 : Dec (IsHex "")
对于第一种情况,只需证明 x : Char
xs : String
rec : StrList xs
--------------------------------------
isItHex_rhs_2 : Dec (IsHex (prim__strCons x xs))
即可:
IsHex "" -> Void
这整个定义是由编译器使用case-split生成的,但它无法检查,声称:
emptyNotHex : IsHex "" -> Void
emptyNotHex IsHexNil impossible
emptyNotHex (IsHexApp _ _ _) impossible
令人惊讶的是,如果我们将第二种情况改为:
(IsHexApp s a b) is a valid case
它也无法编译:
emptyNotHex (IsHexApp s a b) = ?thisIsntEmpty
所以,Idris不认为 Type mismatch between
IsHex (s ++ singleton c0 ++ singleton c1) (Type of IsHexApp s a b)
and
IsHex "" (Expected type)
Specifically:
Type mismatch between
prim__concat s (prim__concat (prim__strCons c0 "") (prim__strCons c1 ""))
and
""Unification failure
,但它认为它的任何实现都是类型错误?哈!混乱。让我们忘记现在,并尝试证明第二个分支。让我们开始将impossible
应用于isItHex
:
xs
错误:
isItHex (strCons x xs) | (SCons x rec) = let foo = isItHex xs in ?isItHex_rhs_2
什么!但是Main.isItHex is possibly not total due to: with block in Main.isItHex
涵盖了所有情况!在这一点上,我注意到我有太多的并行问题,并决定放弃并问。这是我第一次对伊德里斯的非黑色部分进行更广泛的体验,所以希望有人能够揭示我可能做错的一些事情。
答案 0 :(得分:1)
我会尝试一些不那么直接的东西。如果它不在标准库中(例如,Agda的Any
具有可判定性证明),而不是枚举大数据类型中的nybbles,而是构建一些基础结构以在列表/集合中断言元素。
更通用的工作 - 依赖类型中有太多细节,太多细节使事情变得混乱。当你抽象地工作时,你消除了自由度。例如。为列表构建通用All
谓词,以及EvenLength
谓词。证明每个人的简单后果。
我也会尽可能避免担心最初的0x
- 当然不要把它放在数据类型的基本情况中。它属于解析和序列化;使用它就好像是数据一样是不必要的麻烦。