简体   繁体   English

GADT与数据类型的Haskell模式匹配

[英]Haskell pattern matching on GADTs with Data Kinds

I have found that I really like combining GADTs with Data Kinds, as it gives me further type safety than before (for most uses, almost as good as Coq, Agda et al.). 我发现我真的很喜欢将GADT与Data Kinds结合起来,因为它比以前更能提供类型安全性(对于大多数用途,几乎与Coq,Agda等人一样好)。 Sadly, pattern matching fails on the simplest of examples, and I could think of no way to write my functions except for type classes. 遗憾的是,模式匹配在最简单的示例中失败了,我认为除了类型类之外我无法编写我的函数。

Here's an example to explain my sorrow: 这是一个解释我的悲伤的例子:

data Nat = Z | S Nat deriving Eq

data Le :: Nat -> Nat -> * where
    Le_base :: Le a a
    Le_S :: Le a b -> Le a (S b)

class ReformOp n m where
    reform :: Le (S n) (S m) -> Le n m

instance ReformOp a a where
    reform Le_base = Le_base

instance ReformOp a b => ReformOp a (S b) where
    reform (Le_S p) = Le_S $ reform p

class TransThm a b c where
    trans :: Le a b -> Le b c -> Le a c

instance TransThm a a a where
    trans = const

instance TransThm a a b => TransThm a a (S b) where
    trans Le_base (Le_S p) = Le_S $ trans Le_base p

instance (TransThm a b c, ReformOp b c) => TransThm a (S b) (S c) where
    trans (Le_S p) q = Le_S $ trans p $ reform q

We have 2 type classes (one for the theorem, one for a utility operation) and 5 instances - just for a trivial theorem. 我们有2个类型类(一个用于定理,一个用于实用操作)和5个实例 - 仅用于一个简单的定理。 Ideally, Haskell could look at this function: 理想情况下,Haskell可以查看此函数:

-- not working, I understand why
trans :: Le a b -> Le b c -> Le a c
trans Le_base Le_base = Le_base
trans Le_base (Le_S p) = Le_S $ trans Le_base p
trans (Le_S p) q = Le_S $ trans p $ reform q

And type-check each clause on its own, and per-call decide which cases are possible (thus worth trying to match) and which are not, so when calling trans Le_base Le_base Haskell will notice that only the first case allows for the three variables to be the same, and only attempt matching on the first clause. 并且trans Le_base Le_base检查每个子句,并且每次调用决定哪些情况是可能的(因此值得尝试匹配),哪些不是,所以当调用trans Le_base Le_base Haskell将注意到只有第一种情况允许三个变量是相同的,只尝试匹配第一个条款。

I don't see how your pattern-matching definition of trans would work in Agda or Coq. 我怎么没看到你的模式匹配定义trans将在阿格达或勒柯克工作。

If you write the following instead, it works: 如果您改为编写以下内容,则可以:

reform :: Le (S n) (S m) -> Le n m
reform Le_base         = Le_base
reform (Le_S Le_base)  = Le_S Le_base
reform (Le_S (Le_S p)) = Le_S (reform (Le_S p))

trans :: Le a b -> Le b c -> Le a c
trans Le_base  q        = q
trans (Le_S p) Le_base  = Le_S p
trans (Le_S p) (Le_S q) = Le_S (trans p (reform (Le_S q)))

Of course, you could also more directly define: 当然,您还可以更直接地定义:

trans :: Le a b -> Le b c -> Le a c
trans p Le_base  = p
trans p (Le_S q) = Le_S (trans p q)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM