如何将一个大的模式匹配拆分成多个模块?

How to split a big pattern match into multiple modules?

用例:我有一个基于 XML 的小型游戏引擎。每个 XML 元素都应该被解析。有 <deck><dice> 等元素。现在,我有一个巨大的模式匹配子句,内容如下

match xml_element with
| Xml.Element ("deck", [("some_attribute", value)], card_children) ->
    ...
| Xml.Element ("dice", ...

它还在继续。我想把它分成模块,这样我就有了一个 Deck 模块、一个 Dice 模块等等。如何正确匹配 XML 元素并调用不同的模块?使用我迭代的模块列表和 return None 如果每个特定模块内没有匹配项?

我建议使用嵌套模式匹配:

match xml_element with
| Xml.Element ("deck", attributes, card_children) -> match attributes with
   | [("some_attribute", value)] -> …
   | …
| Xml.Element ("dice", attributes, dice_children) -> …
| …

然后你可以将内部的重构为辅助函数,最后将它们移动到自己的模块中。

也许extensible variant type可以帮到你。它们允许您使用 += 构造扩展变体类型。 假设您有以下类型:

type thing = .. (* type thing is open, we can later add constructors to it *)

let handle_thing = function
| _ -> failwith "unknown constructor"

type thing += Dice (* we add the constructor Dice to our type thing *)

let handle_thing = function
  | Dice -> print_string "i handle dice"
  | x -> handle_thing x

type thing += Deck (* we add the constructor Deck to our type thing *)

let handle_thing = function
  | Deck -> print_string "i handle deck"
  | x -> handle_thing x

这允许您在 实现其处理的同时 逐步扩展您的类型。你当然可以把整个事情分成几个模块。

但是,请注意(来自文档)

pattern matching on an extensible variant type requires a default case to handle unknown variant constructors.

Drup (Gabriel Radanne) 在 IRC 上的回答:

let l = [Mod1.f; Mod2.f; Mod3.f]

然后你按顺序尝试每一个。

所有函数必须具有相同的签名

是"poor man's modular patter match" :)

但这是经典技术

它最常用于模块化错误处理,尤其是在编译器中

编辑:自动填充列表的方法是在每个模块中通过 "register functions"、let _ ...