クラスなしで帰納的に型の等価性を証明する方法は?


8

型レベルリストの結合性を証明するために、制約を実行せずに同等の型間で変換できるようにしています。

連結の標準的な定義を仮定すると、

type family (++) (xs :: [k]) (ys :: [k]) :: [k] where
  '[] ++ ys = ys
  (x ': xs) ++ ys = x ': (xs ++ ys)

機能が与えられたとしましょう:

given :: forall k (a :: [k]) (b :: [k]) (c :: [k]). Proxy ((a ++ b) ++ c)
given = Proxy  -- Proxy is just an example

そして、私はこの関数を呼び出して、次に関連性を使用したいと思います:

my :: forall k (a :: [k]) (b :: [k]) (c :: [k]). Proxy (a ++ (b ++ c))
my = given @k @a @b @c  -- Couldn't match type ‘(a ++ b) ++ c’ with ‘a ++ (b ++ c)’

この型の等価性はささいなことではないので、コンパイラーがそれを理解しなくても驚くことではありませんが、証明することはできます!残念ながら、コンパイラをどのように説得できるかわかりません。

私の自然な最初の考えは次のようなことをすることです:

proof :: forall k (a :: [k]) (b :: [k]) (c :: [k]). (a ++ (b ++ c)) :~: ((a ++ b) ++ c)
proof = _

次に、関数を次のように変更します。

my :: forall k (a :: [k]) (b :: [k]) (c :: [k]). Proxy (a ++ (b ++ c))
my = case proof @k @a @b @c of Refl -> given @k @a @b @c

しかし、私はまだ定義するproof必要があり、そのために型引数の帰納を実行する必要があります。私が知っているHaskellで型の帰納を行う唯一の方法は、型クラスを定義することですが、次に、対応しない制約をの型に追加するmy必要があります。given結果は「実装の詳細」になります。

安全でない仮説に頼ることなく、Haskellでこの種の型の等価性を証明する方法はありますか?


1
これは依存型のユースケースになりますが、Haskellにはありません。おそらく型クラスを通じて、(パターンマッチングと再帰を可能にするために)シングルトンに頼る必要があります。(a++(b++c)) :~: ((a++b)++c)シングルトン引数やタイプクラスの制約を追加しないと、タイプの非ボトムタームを記述できないと思います。
カイ

回答:


6

いいえ、これは真実ではないため、型クラス制約なしではこれを証明できません。特に、これは反例です:

Any ++ ([] ++ []) -- reduces to Any ++ []
(Any ++ []) ++ [] -- does not reduce

の(愚かな)存在をAny除外するには、Anyインスタンスを持たない型クラスを使用する必要があります。他に選択肢はありません。


ああ、右、私は忘れておくAny。私は私の定義で種類の注釈があることを望んでいた:( ++それは本当だ保証するだろうが、Any明らかにこれ壊す。
kirelagin

1
Any基本的には単なるundefinedタイプレベルではないですか?後者が存在しないふりをすることは道徳的に正しいので、なぜ前者に対して同じようにできないのですか?
ジョセフ・サイブル復活モニカ

4
@ JosephSible-ReinstateMonicaもちろん、私たちはあなたが好きなふりをすることができます。そして、型レベルのふりを計算レベルに変換する方法は、を使用することunsafeCoerceです。しかし、質問はを回避することを明示的に要求しているためunsafeCoerce、結局のところ、私たちは偽装することはできません。
ダニエルワグナー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.