不規則な穴タイプの解決


105

私は最近、タイプホールとプルーフのパターンマッチングを組み合わせることで、HaskellでAgdaのような素晴らしいエクスペリエンスが提供されることを発見しました。例えば:

{-# LANGUAGE
    DataKinds, PolyKinds, TypeFamilies, 
    UndecidableInstances, GADTs, TypeOperators #-}

data (==) :: k -> k -> * where
    Refl :: x == x

sym :: a == b -> b == a
sym Refl = Refl 

data Nat = Zero | Succ Nat

data SNat :: Nat -> * where
    SZero :: SNat Zero
    SSucc :: SNat n -> SNat (Succ n)

type family a + b where
    Zero   + b = b
    Succ a + b = Succ (a + b)

addAssoc :: SNat a -> SNat b -> SNat c -> (a + (b + c)) == ((a + b) + c)
addAssoc SZero b c = Refl
addAssoc (SSucc a) b c = case addAssoc a b c of Refl -> Refl

addComm :: SNat a -> SNat b -> (a + b) == (b + a)
addComm SZero SZero = Refl
addComm (SSucc a) SZero = case addComm a SZero of Refl -> Refl
addComm SZero (SSucc b) = case addComm SZero b of Refl -> Refl
addComm sa@(SSucc a) sb@(SSucc b) =
    case addComm a sb of
        Refl -> case addComm b sa of
            Refl -> case addComm a b of
                Refl -> Refl 

本当に素晴らしいのは、Refl -> exp構造の右側をタイプホールに置き換えることができ、ホールターゲットタイプが証明で更新さrewriteれることです。Agda のフォームとほぼ同じです。

ただし、ホールが更新に失敗することがあります。

(+.) :: SNat a -> SNat b -> SNat (a + b)
SZero   +. b = b
SSucc a +. b = SSucc (a +. b)
infixl 5 +.

type family a * b where
    Zero   * b = Zero
    Succ a * b = b + (a * b)

(*.) :: SNat a -> SNat b -> SNat (a * b)
SZero   *. b = SZero
SSucc a *. b = b +. (a *. b)
infixl 6 *.

mulDistL :: SNat a -> SNat b -> SNat c -> (a * (b + c)) == ((a * b) + (a * c))
mulDistL SZero b c = Refl
mulDistL (SSucc a) b c = 
    case sym $ addAssoc b (a *. b) (c +. a *. c) of
        -- At this point the target type is
        -- ((b + c) + (n * (b + c))) == (b + ((n * b) + (c + (n * c))))
        -- The next step would be to update the RHS of the equivalence:
        Refl -> case addAssoc (a *. b) c (a *. c) of
            Refl -> _ -- but the type of this hole remains unchanged...

また、ターゲットタイプが必ずしもプルーフ内に並ぶとは限りませんが、Agdaから全体を貼り付けても、問題はありません。

mulDistL' :: SNat a -> SNat b -> SNat c -> (a * (b + c)) == ((a * b) + (a * c))
mulDistL' SZero b c = Refl
mulDistL' (SSucc a) b c = case
    (sym $ addAssoc b (a *. b) (c +. a *. c),
    addAssoc (a *. b) c (a *. c),
    addComm (a *. b) c,
    sym $ addAssoc c (a *. b) (a *. c),
    addAssoc b c (a *. b +. a *. c),
    mulDistL' a b c
    ) of (Refl, Refl, Refl, Refl, Refl, Refl) -> Refl

これがなぜ起こるのか(または私がどのようにして堅牢な方法で証明の書き換えを行うことができるか)のアイデアはありますか?


8
少し期待していませんか?等価性証明のパターンマッチングは、(双方向の)等価性を確立しています。ターゲットタイプに適用する場所と方向を明確にしていません。たとえば、sym呼び出しを省略してmulDistL'も、コードは引き続きチェックします。
kosmikus 14

1
かなり多分私は期待しすぎています。ただし、多くの場合、Agdaと同じように機能するため、動作の規則性を理解することは依然として有用です。問題はタイプチェッカーの腸に深く関与している可能性が高いため、私は楽観的ではありません。
アンドラス・コバックス

1
それはあなたの質問に少し直交していますが、アグダの一連の等式推論コンビネータを使用することでこれらの証明を引き出すことができます。Cf. この概念実証
ガレ

回答:


1

そのようなすべての可能な値を生成したい場合は、提供された境界または指定された境界を使用して、それを行う関数を作成できます。

型レベルのChurch Numeralsなどを使用して、これらの作成を強制することは非常に可能ですが、たいていの場合、必要とするもの/必要なものに対しては、あまりにも多くの作業です。

これはあなたが望むものではないかもしれません(つまり、「z = 5-x-yなので(x、y)だけを使用することを除いて」)が、有効にするために型レベルに何らかの強制的な制限を課すよりも理にかなっています値。


-3

これは、値が実行時に決定されるために発生します。これは、実行時に入力されたものに応じて値の変換を引き起こす可能性があるため、穴はすでに更新されていると想定しています。


3
もちろん、値は実行時に決定されますが、問題とは関係ありません。必要な情報は、GADTのパターンマッチングからすでに利用可能です。
int_index 2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.