私は "異種ツリー"をモデル化しようとしています。ノードが異なる「種類」を持っており、それぞれの「種類」が、彼らは含まれていてもよい子どもたちの「種類」に制限されているツリー:高次関数を持つGADTを使用する
type id = string
type block
type inline
type _ node =
| Paragraph : id * inline node list -> block node
| Strong : id * inline node list -> inline node
| Text : id * string -> inline node
ツリーは次のように定義することができます。
let document =
Paragraph ("p1", [
Text ("text1", "Hello ");
Strong ("strong1", [
Text ("text2", "Glorious")
]);
Text ("text3", " World!")
])
これは通常、ノードの "種類"ごとに別々のバリアントを使用して行われますが、すべての種類のノードでパターンが一致する高次関数を使用してツリーを操作できるように、GADTとして定義しようとしています:
function
| Text ("text2", _) ->
Some (Text ("text2", "Dreadful"))
| _ ->
None
私が持っている問題は、上記の高次関数を受け入れ、すべてのノードに適用する関数を定義することです。これまでのところ私はこれがあります。
let rec replaceNode (type a) (f: a node -> a node option) (node: a node): a node = match f node with | Some otherNode -> otherNode | None -> match node with | Paragraph (id, children) -> Paragraph (id, (List.map (replaceNode f) children)) | Strong (id, children) -> Strong (id, (List.map (replaceNode f) children)) | Text (_, _) -> node
をしかし、コンパイラは私に強調表示された行
This expression has type block node -> a node option but an expression was expected of type block node -> a node option This instance of block is ambiguous: it would escape the scope of its equation
に次のエラーを与えるか、私は'a node -> 'a node option
へf
の種類を変更する場合、私は
This expression has type a node but an expression was expected of type a node The type constructor a would escape its scope
ローカルの抽象型(または実際にはGADT)は完全に理解できませんが、これらのエラーはt彼がタイプするのは、名前が示唆するように、「地方」であり、外側の多態性はそれを「流出」させるだろうと思いますか?これを行うことも可能です(と、「これは」私は高階関数でGADT上のパターンマッチにを意味だと思うことで、私はよ:
だから、私の質問は、何よりもまず、ですそれが実際の問題であるかどうかは分かりません)?
Playground with all the code here
ありがとう、それは素晴らしい答えです!最初の問題は、私が直感的に解決しようとしていた問題です。 2番目の問題は、私がこれらの概念の構文を正しく理解して区別できず、混乱させていることによるものです。あまりにもそれをクリアしていただきありがとうございます。しかし、1つの要素が欠けているように見えますが、高次関数をどのように定義するのでしょうか?現在のところ、 "このフィールド値には型インラインノード - >インラインノードオプションがあります。これは' a 'より一般的ではありません。'ノード - > 'ノードオプション' {'f = function | ...} '。 – glennsl
関数を変数にバインドすると、型 'a型で注釈を付けることができます。ノード→ノードオプション」を選択すると、動作します。しかし、匿名関数に対してこれを行うより便利な方法がありますか? – glennsl
匿名関数の場合、ローカル抽象表記だけを使用すると '(fun(type a)(x:a node):ノードオプション - > xと...)'を実行します。しかし、 'fun ...:result_type - >'アノテーションにはOCaml≧4.03が必要です。 – octachron