idris - 如何在 Idris 中定义仅包含某些值组合的对类型
问题描述
我试图通过尝试一些超出我深度的方法来了解 Idris 中的依赖类型。如果我犯了任何愚蠢的错误,请多多包涵。
给定简单类型
data Letter = A | B | C | D
我想定义一个LPair
包含一对Letter
这样的类型,只有“相邻”字母可以配对。例如,B
可以与A
or配对C
,但不能与D
or 本身配对。它环绕,因此A
被D
视为邻居。
在实践中,给定的x : Letter
和y : Letter
, mklpair x y
将等同于mklpair y x
,但我不确定该属性是否可以或应该反映在类型中。
制作这种类型的最佳方法是什么?
解决方案
最直接的方法是创建一个(Letter, Letter)
满足谓词的元素的子集(a, b : Letter) -> Either (Next a b) (Next b a)
,其中Next
is 只是右边的邻居:
data Letter = A | B | C | D
data Next : Letter -> Letter -> Type where
AB : Next A B
BC : Next B C
CD : Next C D
DA : Next D A
Neighbour : Letter -> Letter -> Type
Neighbour a b = Either (Next a b) (Next b a)
LPair : Type
LPair = (p : (Letter, Letter) ** Neighbour (fst p) (snd p))
mklpair : (a : Letter) -> (b : Letter) -> {auto prf : Neighbour a b} -> LPair
mklpair a b {prf} = ((a, b) ** prf)
注意:这种方法既好又简单,但是一旦您实现了一个决定是否彼此相邻的函数,您将需要围绕a
案例:b
(number of letters)^3
isNext : (a : Letter) -> (b : Letter) -> Dec (Next a b)
isNext A A = No nAA where
nAA : Next A A -> Void
nAA AB impossible
nAA BC impossible
nAA CD impossible
nAA DA impossible
isNext A B = Yes AB
...
如果您有很多字母并且需要决策函数,那么通常的方法是将您的数据映射到递归类型,例如Nat
. 由于您的模案例(Next D A
),您需要一个包装器,例如:
data NextN : Nat -> Nat -> Nat -> Type where
NextS : {auto prf : (S a) `LTE` m} -> NextN m a (S a) -- succ in mod m
NextZ : {auto prf : Not ((S a) `LTE` m)} -> NextN m a Z -- wrap around
LToN : Letter -> Nat
LToN A = 0
LToN B = 1
LToN C = 2
LToN D = 3
LNeighbour : Letter -> Letter -> Type
LNeighbour x y =
let a = LToN x
b = LToN y
in Either (NextN 3 a b) (NextN 3 b a)
LNPair : Type
LNPair = (p : (Letter, Letter) ** LNeighbour (fst p) (snd p))
mklnpair : (a : Letter) -> (b : Letter) -> {auto prf : LNeighbour a b} -> LNPair
mklnpair a b {prf} = ((a, b) ** prf)
NextS
并且NextZ
您只需要检查两种情况,而不是为每个字母检查一种情况。
推荐阅读
- ios - 如何从 SafariViewController 快速获取文本到我们的应用程序?
- python - Python:按一列分组,从另一列获取计数
- php - 通过 PHP 读取 FTP 目录(列表) - 名称错误
- python - 可选的虚拟环境创建错误
- sql-server - 计算 SQL Server 中各列的出现次数
- mysql - 获取具有多行和不同状态的数据
- python - 从源代码安装 opencv 时,如何在 pyinstaller 中包含 OpenCV?
- jspdf - doc.autotable.previous 在 jsPDF 中未定义
- google-apps-script - 在谷歌应用脚本中获取当前脚本版本
- r - 是否有 R 函数来查找两条线的交点?