私は専門家ではありませんが、これが私の見解です。
本当のエラーは、メッセージの最後のビットです。
型コンストラクタ Ft はそのスコープをエスケープします
エラー メッセージを理解するために、最初any_foo
に引数をパターン マッチングせずに書き直し、引数の名前を変更して説明を理解しやすくします。
let any_foo arg foo =
let (module F : Foo) = foo in
F.do_with_t arg
ここではファースト クラス モジュールを使用しており、その let ステートメントのスコープ内で変数foo
を新しいmoduleF
にアンパックしています。
arg
この事実から推測できる引数の型を考えてみましょう。明らかに型は ですF.t
が、重要なことに、これは現在のスコープでのみ認識されている型です。これは、 が現在のスコープでのみ認識されているためmodule F
です。
any_foo
結果の関数の型を定義してみましょう。
val any_foo : F.t -> (module Foo) -> unit
そして、あなたの問題がありますF.t
.関数スコープの奥深くから新しく作成された型を公開しようとしています. つまり、呼び出し元が関数内にのみ存在する型を知っていることを期待しています。F.t
または、別の言い方をすれば、型がそのスコープをより広い対象者に「エスケープ」することを期待しています。
解決策、説明
問題がわかったので、この型が「外側」のスコープに存在し、引数arg
がその型であることをコンパイラに説明する必要があることを認識することができます。
言い換えれば、F
引数の型が新しいモジュール内arg
の型と等しいことを示すために、新しく作成されたモジュールに制約を追加する必要があります。そのために、ローカル抽象型を使用できます。t
F
同じ関数を続けて、ローカルに抽象型を追加し、それでa
モジュールを制約できますF
。
let (type a) any_foo arg foo =
let (module F : Foo with type t = a) = foo in
F.do_with_t arg
今の型を考えてみましょうany_foo
。
val any_foo : 'a -> (module Foo with type t = 'a) -> unit
問題ありません。
完全を期すために、パターン マッチングのバージョンに戻りましょう。
let (type a) any_foo arg (module F : Foo with type t = a) =
F.do_with_t arg