シナリオは次のとおりです。型シグネチャを使用していくつかのコードを記述しましたが、GHCは一部のx
とについてx〜yを推定できませんでしたy
。通常、GHCに骨を投げて、関数の制約に同型を単に追加できますが、これはいくつかの理由で悪い考えです。
- コードの理解を強調するものではありません。
- 最終的に5つの制約で十分な場合があります(たとえば、5がもう1つの特定の制約によって暗示されている場合)
- 何か間違ったことをしたり、GHCが役に立たなかったりすると、偽の制約になる可能性があります。
ケース3との戦いに数時間費やしたところです。私はで遊んでおりsyntactic-2.0
、でshare
定義されているバージョンと同様に、ドメインに依存しないバージョンのを定義しようとしていましたNanoFeldspar.hs
。
私はこれを持っていました:
{-# LANGUAGE GADTs, FlexibleContexts, TypeOperators #-}
import Data.Syntactic
-- Based on NanoFeldspar.hs
data Let a where
Let :: Let (a :-> (a -> b) :-> Full b)
share :: (Let :<: sup,
Domain a ~ sup,
Domain b ~ sup,
SyntacticN (a -> (a -> b) -> b) fi)
=> a -> (a -> b) -> a
share = sugarSym Let
そしてGHC could not deduce (Internal a) ~ (Internal b)
、それは確かに私が目指していたものではありません。だから、私が意図しないコードを書いた(制約が必要だった)か、あるいは私が書いた他の制約のためにGHCがその制約を望んでいた。
(Syntactic a, Syntactic b, Syntactic (a->b))
制約リストに追加する必要がありましたが、どれも意味しません(Internal a) ~ (Internal b)
。基本的に、正しい制約に出くわしました。それらを見つけるための体系的な方法はまだありません。
私の質問は:
- なぜGHCはその制約を提案したのですか?構文のどこにも制約はあり
Internal a ~ Internal b
ませんが、GHCはどこからそれを引き出しましたか? - 一般的に、GHCが必要とする制約の起源を追跡するためにどのような手法を使用できますか?私自身が発見できる制約についても、私のアプローチは本質的に、再帰的制約を物理的に書き留めることによって、問題のあるパスを力ずくで強制します。このアプローチは基本的に制約の無限のウサギの穴を掘り下げており、私が想像できる最も効率の悪い方法についてです。
a
とb
バインドされている- -あなたのコンテキストの型シグネチャの外を見てa -> (a -> b) -> a
、ではありませんa -> (a -> b) -> b
。多分それだけですか?制約ソルバーを使用すると、それらはどこでも推移的等式に影響を与える可能性がありますが、エラーは通常、制約が発生した場所に「近い」場所を示します。@jozefgを使用してもかっこいいです-制約にタグなどで注釈を付けて、それらがどこから来たかを示すことはできますか?:s