gpt4 book ai didi

haskell - 我可以向类型检查器提供有关 GHC 7.6 中归纳自然的证明吗?

转载 作者:行者123 更新时间:2023-12-03 13:31:53 24 4
gpt4 key购买 nike

GHC 7.6.1 带有用于在类型级别进行编程的新功能,包括 datatype promotion .以那里关于类型级自然数和向量的示例为例,我希望能够在依赖于基本算术定律的向量上编写函数。

不幸的是,尽管我想要的定律通常很容易通过案例分析和归纳来证明归纳自然,但我怀疑我能否说服类型检查器。举个简单的例子,对下面的朴素反向函数进行类型检查需要证明 n + Su Ze ~ Su n .

有什么方法可以提供该证明,还是我现在真的处于成熟的依赖类型领域?

{-# LANGUAGE DataKinds, KindSignatures, GADTs, TypeFamilies, TypeOperators #-}

data Nat = Ze | Su Nat

data Vec :: * -> Nat -> * where
Nil :: Vec a Ze
Cons :: a -> Vec a n -> Vec a (Su n)

type family (m :: Nat) + (n :: Nat) :: Nat

type instance Ze + n = n
type instance (Su m + n) = Su (m + n)

append :: Vec a m -> Vec a n -> Vec a (m + n)
append Nil ys = ys
append (Cons x xs) ys = Cons x (append xs ys)

rev :: Vec a n -> Vec a n
rev Nil = Nil
rev (Cons x xs) = rev xs `append` Cons x Nil

最佳答案

(注意:我只对任何代码进行了类型检查(并没有实际运行)。)

方法 1

实际上,您可以通过将证明存储在 GADT 中来对其进行操作。您需要打开 ScopedTypeVariables使这种方法起作用。

data Proof n where
NilProof :: Proof Ze
ConsProof :: (n + Su Ze) ~ Su n => Proof n -> Proof (Su n)

class PlusOneIsSucc n where proof :: Proof n
instance PlusOneIsSucc Ze where proof = NilProof
instance PlusOneIsSucc n => PlusOneIsSucc (Su n) where
proof = case proof :: Proof n of
NilProof -> ConsProof proof
ConsProof _ -> ConsProof proof

rev :: PlusOneIsSucc n => Vec a n -> Vec a n
rev = go proof where
go :: Proof n -> Vec a n -> Vec a n
go NilProof Nil = Nil
go (ConsProof p) (Cons x xs) = go p xs `append` Cons x Nil

实际上, Proof 的动机可能很有趣。上面的类型,我最初只是
data Proof n where Proof :: (n + Su Ze) ~ Su n => Proof n

但是,这不起作用:GHC 正确地提示说,仅仅因为我们知道 (Su n)+1 = Su (Su n)并不意味着我们知道 n+1 = Su n ,这是我们对 rev 进行递归调用所需要知道的。在 Cons案子。所以我不得不扩展 Proof 的含义。包括对直到并包括 n 的自然人所有等式的证明——本质上与从感应到强感应的强化过程类似。

方法二

经过一番思考,我意识到这门课有点多余;这使得这种方法特别好,因为它不需要任何额外的扩展(甚至 ScopedTypeVariables )并且不会对 Vec 的类型引入任何额外的约束。 .
data Proof n where
NilProof :: Proof Ze
ConsProof :: (n + Su Ze) ~ Su n => Proof n -> Proof (Su n)

proofFor :: Vec a n -> Proof n
proofFor Nil = NilProof
proofFor (Cons x xs) = let rec = proofFor xs in case rec of
NilProof -> ConsProof rec
ConsProof _ -> ConsProof rec

rev :: Vec a n -> Vec a n
rev xs = go (proofFor xs) xs where
go :: Proof n -> Vec a n -> Vec a n
go NilProof Nil = Nil
go (ConsProof p) (Cons x xs) = go p xs `append` Cons x Nil

方法 3

或者,如果您切换 rev 的实现稍微将最后一个元素放到列表的反向初始段上,那么代码看起来会更简单一些。 (这种方法也不需要额外的扩展。)
class Rev n where
initLast :: Vec a (Su n) -> (a, Vec a n)
rev :: Vec a n -> Vec a n

instance Rev Ze where
initLast (Cons x xs) = (x, xs)
rev x = x

instance Rev n => Rev (Su n) where
initLast (Cons x xs) = case initLast xs of
(x', xs') -> (x', Cons x xs')
rev as = case initLast as of
(a, as') -> Cons a (rev as')

方法 4

就像方法 3,但再次观察到类型类不是必需的。
initLast :: Vec a (Su n) -> (a, Vec a n)
initLast (Cons x xs) = case xs of
Nil -> (x, Nil)
Cons {} -> case initLast xs of
(x', xs') -> (x', Cons x xs')

rev :: Vec a n -> Vec a n
rev Nil = Nil
rev xs@(Cons {}) = case initLast xs of
(x, xs') -> Cons x (rev xs')

关于haskell - 我可以向类型检查器提供有关 GHC 7.6 中归纳自然的证明吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12442858/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com