我试图建模一个“异构树”,即。一棵树,其中节点具有不同的“种”,每个“种”在孩子们的“种”被限制它们可能包含:使用具有更高阶函数的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
或者,如果我改变的f
类型'a node -> 'a node option
我得到这个错误下面的错误,而不是
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
谢谢,这是一个很好的答案!第一个问题是我直觉上试图解决的问题。第二个问题是由于我没有正确理解和区分这些概念的语法,从而混淆了它们。感谢您清理那个。似乎有一个缺失,但如何定义高阶函数?它现在抱怨说:“这个字段值包含类型内联节点 - >内联节点选项,它比'a。'节点 - >'节点选项'通用性要低'{f = function | ''。 – glennsl
如果我将函数绑定到一个变量,我可以用类型'a来注释它。一个节点 - >一个节点选项',那么它就起作用了。但是,有没有一种更方便的方法来做这个匿名函数? – glennsl
对于一个匿名函数,只使用局部抽象符号工作'(fun(type a)(x:a node):一个节点选项 - >将x与...匹配)''。然而,'fun ...:result_type - >'注释需要OCaml≥4.03。 – octachron