簡體   English   中英

證明自然數的類型級加法的交換性

[英]Proving commutativity of type level addition of natural numbers

我正在使用haskell為依賴類型編程提供的工具。 我已經將一個代表自然數的GADT推廣到了那個級別,並且為了增加自然數而建立了一個類型族。 我還制作了你的標准“嬰兒的第一個依賴類型數據類型”向量,參數化其長度和它包含的類型。 代碼如下:

data Nat where
    Z :: Nat
    S :: Nat -> Nat

type family (a :: Nat) + (b :: Nat) :: Nat where
    Z + n = n
    S m + n = S (m + n)

data Vector (n :: Nat) a where
    Nil :: Vector Z a
    Cons :: a -> Vector n a -> Vector (S n) a

此外,我做了一個append函數,它接受一個m向量,一個n-vetor並返回一個(m + n) - 向量。 這可以和人們希望的一樣有效。 然而,只是為了它,我試圖翻轉它,所以它返回一個(n + m) - 矢量。 這會產生編譯器錯誤,因為GHC無法證明我的添加是可交換的。 我還是比較新的打字家庭,所以我不知道如何自己寫這個證明,或者如果你甚至可以用haskell做的話。

我最初的想法是以某種方式利用類型相等約束,但我不確定如何前進。

所以要明確:我想寫這個功能

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

但它無法編譯

    * Could not deduce: (n + 'Z) ~ n
      from the context: m ~ 'Z
        bound by a pattern with constructor: Nil :: forall a. Vector 'Z a,
                 in an equation for `append'

這是一個完整的解決方案。 警告:包括一些無主。

我們從原始代碼開始。

{-# LANGUAGE TypeFamilies, DataKinds, TypeOperators, GADTs, PolyKinds #-}
{-# OPTIONS -Wall -O2 #-}
module CommutativeSum where

data Nat where
    Z :: Nat
    S :: Nat -> Nat

type family (a :: Nat) + (b :: Nat) :: Nat where
    'Z + n = n
    'S m + n = 'S (m + n)

data Vector (n :: Nat) a where
    Nil :: Vector 'Z a
    Cons :: a -> Vector n a -> Vector ('S n) a

舊的追加類型立即檢查。

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

對於另一個附加,我們需要證明加法是可交換的。 我們首先在類型級別定義相等性,利用GADT。

-- type equality, also works on Nat because of PolyKinds
data a :~: b where
   Refl :: a :~: a

我們引入了單例類型,這樣我們就可以傳遞Nat s並對它們進行模式匹配。

-- Nat singleton, to reify type level parameters
data NatI (n :: Nat) where
  ZI :: NatI 'Z
  SI :: NatI n -> NatI ('S n)

我們可以將每個向量的長度關聯為單個NatI

-- length of a vector as a NatI
vecLengthI :: Vector n a -> NatI n
vecLengthI Nil = ZI
vecLengthI (Cons _ xs) = SI (vecLengthI xs)

現在是核心部分。 我們需要通過歸納證明n + m = m + n 對於某些算術定律,這需要一些引理。

-- inductive proof of: n + Z = n  
sumZeroRight :: NatI n -> (n + 'Z) :~: n
sumZeroRight ZI = Refl
sumZeroRight (SI n') = case sumZeroRight n' of
   Refl -> Refl

-- inductive proof of: n + S m = S (n + m)
sumSuccRight :: NatI n -> NatI m -> (n + 'S m) :~: 'S (n + m)
sumSuccRight ZI _m = Refl
sumSuccRight (SI n') m  = case sumSuccRight n' m of
   Refl -> Refl

-- inductive proof of commutativity: n + m = m + n
sumComm :: NatI n -> NatI m -> (n + m) :~: (m + n)
sumComm ZI m = case sumZeroRight m of Refl -> Refl
sumComm (SI n') m = case (sumComm n' m, sumSuccRight m n') of
   (Refl, Refl) -> Refl

最后,我們可以利用上面的證據來說服GHC按我們的意願鍵入append 請注意,我們可以使用舊類型重用該實現,然后說服GHC它也可以使用新類型。

-- append, with the wanted type
append2 :: Vector m a -> Vector n a -> Vector (n + m) a
append2 xs ys = case sumComm (vecLengthI xs) (vecLengthI ys) of
   Refl -> append xs ys

最后的評論。 與完全依賴類型的語言(比如Coq)相比,我們不得不引入單身人士並花費更多的努力使它們發揮作用(Hasochism的“痛苦”部分)。 作為回報,我們可以簡單地與Refl模式匹配,讓GHC弄清楚如何使用推導出的方程,而不會弄亂依賴匹配(“愉悅”部分)。

總的來說,我認為使用完全依賴類型仍然更容易一些。 如果/當GHC獲得非擦除類型量詞( pi n. ...超出forall n. ... ),可能Haskell將變得更加方便。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM