型レベルリストの結合性を証明するために、制約を実行せずに同等の型間で変換できるようにしています。
連結の標準的な定義を仮定すると、
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でこの種の型の等価性を証明する方法はありますか?
(a++(b++c)) :~: ((a++b)++c)
シングルトン引数やタイプクラスの制約を追加しないと、タイプの非ボトムタームを記述できないと思います。