Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 在构造枚举上荒谬谓词的证明时,有什么技巧可以去掉样板文件吗?_Haskell_Boilerplate_Dependent Type_Idris_Proof Of Correctness - Fatal编程技术网

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定义为一个值级函数,并在适当的地方在校样中使用它吗?