我試圖建模一個「異構樹」,即。一棵樹,其中節點具有不同的「種」,每個「種」在孩子們的「種」被限制它們可能包含:使用具有更高階函數的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