如何将一个大的模式匹配拆分成多个模块?
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 _ ...
。
用例:我有一个基于 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 _ ...
。