Haskell 在构造枚举上荒谬谓词的证明时,有什么技巧可以去掉样板文件吗?
假设我有Haskell 在构造枚举上荒谬谓词的证明时,有什么技巧可以去掉样板文件吗?,haskell,boilerplate,dependent-type,idris,proof-of-correctness,Haskell,Boilerplate,Dependent Type,Idris,Proof Of Correctness,假设我有 data-Fruit=Apple |香蕉|葡萄|橙|柠檬|{许多其他-} 以及该类型的谓词 datawinestock:Fruit->Type where 经典葡萄酒:酿酒葡萄 苹果酒:酿酒苹果 这不适用于香蕉、橘子、柠檬等 它将WineStock定义为水果的谓词WineStock Grape是正确的(因为我们可以构造该类型的值/证明:CanonicalWine)以及WineStock Apple,但是WineStock Banana是错误的,因为该类型没有任何值/证明 那么,我
data-Fruit=Apple |香蕉|葡萄|橙|柠檬|{许多其他-}
以及该类型的谓词
datawinestock:Fruit->Type where
经典葡萄酒:酿酒葡萄
苹果酒:酿酒苹果
这不适用于香蕉、橘子、柠檬等
它将WineStock
定义为水果的谓词WineStock Grape
是正确的(因为我们可以构造该类型的值/证明:CanonicalWine
)以及WineStock Apple
,但是WineStock Banana
是错误的,因为该类型没有任何值/证明
那么,我如何才能有效地使用Not(WineStock香蕉)
,Not(WineStock柠檬)
,等等?似乎除了葡萄和苹果之外,每个水果
构造器,我不得不为葡萄酒
编一个案例,在某个地方,充满了不可能的
s:
实例无人居住(WineStock香蕉),其中
无人居住的经典葡萄酒不可能
无人居住的苹果酒是不可能的
实例无人居住(WineStock Lemon),其中
无人居住的经典葡萄酒不可能
无人居住的苹果酒是不可能的
实例无人居住(WineStock Orange),其中
无人居住的经典葡萄酒不可能
无人居住的苹果酒是不可能的
请注意:
- 代码是重复的
- 当谓词定义增长时,LoC将爆炸,从而获得更多构造函数。想象一下
Not(Sweet Lemon)
证明,假设水果定义中有很多甜的替代品
因此,这种方式似乎不太令人满意,几乎不切实际
还有更优雅的方法吗?@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
Is p x
确保属性p
保存元素x
(我使用了归纳类型而不是类型别名,以便Idris不会在孔的上下文中展开它;这样更容易阅读)
isnt-prf
每当类型检查器能够自动生成pa=False
的证明时(通过Refl
或上下文中的假设),就会取消伪证明prf
一旦你有了这些,你就可以开始定义你的属性,只需要列举积极的案例并添加一个catchall
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
您可以使用适当的决策函数将原始谓词定义为调用Is
的类型别名:
WineStock : Fruit -> Type
WineStock = Is wineFruit
当然,不是
允许您排除不可能的情况:
dismiss : WineStock Orange -> Void
dismiss = isnt
许多古老的Haskell习惯用法在依赖类型的系统中不会改变。“使非法状态不可表示”也适用于类型级别:我认为您甚至不应该能够构造那些不可能的类型。我可能会将这个示例构造为(大致类似)一种水果,它可以酿造葡萄酒data WineFruit=Grape | Apple
和其他水果data Fruit=WineFruit WineFruit |香蕉|橙|柠檬
@BenjaminHodgson,当你想添加PieFruit
时,这种方法开始崩溃,SaladFruit
,WeaponFruit
等。既然您在idris中,为什么要为WineStock
定义数据类型?难道你不能将isWineStock定义为一个值级函数,并在适当的地方在校样中使用它吗?