Mercury语言含自由变量的高阶语法规则实现咨询
在Mercury中实现带自由变量的高阶语法规则
Mercury的静态模式检查严格限制高阶谓词中lambda的非局部变量必须为ground,这是它和Prolog动态语义的核心差异之一。要实现你需要的带自由变量的语法抽象,不用宏的话,可以通过以下几种方式解决:
1. 将变量作为谓词参数传递(最直接方案)
核心思路是把原本的自由变量X转化为语法谓词的显式参数,避免它成为lambda的非局部变量。
步骤1:定义带参数的语法谓词
先把day_of_week定义为接受结果变量作为第一个参数的谓词:
:- pred day_of_week(int, io.state, io.state). :- mode day_of_week(out, in, out) is det. day_of_week(1, "monday" ++ Rest, Rest). day_of_week(2, "tuesday" ++ Rest, Rest). % ... 其他星期几的规则
步骤2:定义支持参数化谓词的parenthesised
调整parenthesised,让它接受一个带结果参数的语法谓词,以及用于接收绑定值的变量:
:- pred parenthesised((T, io.state, io.state) => pred, T, io.state, io.state). :- mode parenthesised(pred(out, in, out) is det, out, in, out) is det. parenthesised(GrammarPred, Val, In, Out) :- % 解析左括号 string.read_char('(', In, Mid1), % 调用语法谓词,绑定Val到对应值 GrammarPred(Val, Mid1, Mid2), % 解析右括号 string.read_char(')', Mid2, Out).
调用方式
现在可以直接调用,X会被正确绑定为2:
parenthesised(day_of_week, X, "(tuesday)", Rest)
2. 使用存在类型封装语法规则(更抽象的方案)
如果希望语法规则的结构更模块化,可以用Mercury的存在类型封装带参数的语法谓词,让调用风格更接近你原本的预期。
步骤1:定义存在类型的语法封装
:- type grammar(T) ---> grammar((T, io.state, io.state) => pred).
步骤2:封装day_of_week为语法实例
:- func day_of_week_grammar = grammar(int). day_of_week_grammar = grammar(day_of_week).
步骤3:调整parenthesised接受封装后的语法类型
:- pred parenthesised(grammar(T), T, io.state, io.state). :- mode parenthesised(in, out, in, out) is det. parenthesised(grammar(GrammarPred), Val, In, Out) :- string.read_char('(', In, Mid1), GrammarPred(Val, Mid1, Mid2), string.read_char(')', Mid2, Out).
调用方式
parenthesised(day_of_week_grammar, X, "(tuesday)", Rest)
关键原理说明
Mercury报错的本质是:高阶谓词中的匿名谓词(lambda)的非局部变量必须是ground的——静态模式检查需要确保调用lambda时,这些变量的实例化状态是确定的,避免运行时的模式冲突。上面的方案都是通过消除非局部自由变量(把变量转为显式参数)或者封装变量的存在性,让代码符合Mercury的模式规则,同时实现你需要的变量绑定效果。
内容的提问来源于stack exchange,提问作者Pavel Bazant
相关产品推荐
相关产品推荐

