uli*_*tko 11 haskell boilerplate dependent-type idris proof-of-correctness
让我说我有
data Fruit = Apple | Banana | Grape | Orange | Lemon | {- many others -}
Run Code Online (Sandbox Code Playgroud)
和该类型的谓词,
data WineStock : Fruit -> Type where
CanonicalWine : WineStock Grape
CiderIsWineToo : WineStock Apple
Run Code Online (Sandbox Code Playgroud)
这并不适用于Banana
,Orange
,Lemon
和其他人.
它可以说,这定义WineStock
为上一个谓语Fruit
; WineStock Grape
是真的(因为我们可以构造该类型的值/证明:) CanonicalWine
以及WineStock Apple
但是WineStock Banana
是假的,因为该类型不是任何值/证明所居住的.
那么,我该怎么去使用有效Not (WineStock Banana)
,Not (WineStock Lemon)
等等?似乎对于每个Fruit
构造函数除了Grape
和Apple
,我不得不编写一个案例分裂WineStock
,某处,充满impossible
s:
instance Uninhabited (WineStock Banana) where
uninhabited CanonicalWine impossible
uninhabited CiderIsWineToo impossible
instance Uninhabited (WineStock Lemon) where
uninhabited CanonicalWine impossible
uninhabited CiderIsWineToo impossible
instance Uninhabited (WineStock Orange) where
uninhabited CanonicalWine impossible
uninhabited CiderIsWineToo impossible
Run Code Online (Sandbox Code Playgroud)
注意:
Not (Sweet Lemon)
证明,假设Fruit
定义中有许多甜蜜的选择.所以,这种方式似乎并不令人满意,几乎不切实际.
有更优雅的方法吗?
@slcv 是对的:使用计算水果是否满足属性的函数而不是构建各种归纳谓词将允许您摆脱这种开销。
这是最小的设置:
data Is : (p : a -> Bool) -> a -> Type where
Indeed : p x = True -> Is p x
isnt : {auto eqF : p a = False} -> Is p a -> b
isnt {eqF} (Indeed eqT) = case trans (sym eqF) eqT of
Refl impossible
Run Code Online (Sandbox Code Playgroud)
Is p x
确保属性p
保留元素x
(我使用归纳类型而不是类型别名,以便 Idris 不会在孔的上下文中展开它;这样更容易阅读)。
isnt prf
prf
每当类型检查器能够p a = False
自动生成证明(通过Refl
上下文中的假设)时,就会驳回虚假证明。
一旦有了这些,您就可以通过仅枚举正面案例并添加一个包罗万象的方式来开始定义您的属性
wineFruit : Fruit -> Bool
wineFruit Grape = True
wineFruit Apple = True
wineFruit _ = False
weaponFruit : Fruit -> Bool
weaponFruit Apple = True
weaponFruit Orange = True
weaponFruit Lemon = True
weaponFruit _ = False
Run Code Online (Sandbox Code Playgroud)
您可以将原始谓词定义为使用Is
适当的决策函数调用的类型别名:
WineStock : Fruit -> Type
WineStock = Is wineFruit
Run Code Online (Sandbox Code Playgroud)
果然,它isnt
可以让你忽略不可能的情况:
dismiss : WineStock Orange -> Void
dismiss = isnt
Run Code Online (Sandbox Code Playgroud)