如何证明字符串是十六进制格式?

时间:2018-01-06 01:29:24

标签: functional-programming idris theorem-proving

如何使用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 涵盖了所有情况!在这一点上,我注意到我有太多的并行问题,并决定放弃并问。这是我第一次对伊德里斯的非黑色部分进行更广泛的体验,所以希望有人能够揭示我可能做错的一些事情。

1 个答案:

答案 0 :(得分:1)

我会尝试一些不那么直接的东西。如果它不在标准库中(例如,Agda的Any具有可判定性证明),而不是枚举大数据类型中的nybbles,而是构建一些基础结构以在列表/集合中断言元素。

更通用的工作 - 依赖类型中有太多细节,太多细节使事情变得混乱。当你抽象地工作时,你消除了自由度。例如。为列表构建通用All谓词,以及EvenLength谓词。证明每个人的简单后果。

我也会尽可能避免担心最初的0x - 当然不要把它放在数据类型的基本情况中。它属于解析和序列化;使用它就好像是数据一样是不必要的麻烦。