我试图在Prolog中编写一个
adaptive parser:换句话说,一个可以在运行时修改自己的解析规则的解析器.
为了做到这一点,我需要在运行时生成新的谓词,但我不确定这是否可行.是否可以编写一个带有这样一个列表的谓词:
generate_dcg_rule([A," is greater than ",B]).
…然后生成一个像这样的新谓词?
expr(A,B) --> symbol(A),symbol(B).
解决方法
是的,这很容易实现.
Prolog是一种非常动态的语言,您可以使用例如assertz / 1在运行时声明任意子句.
您可以使用通常用于执行此操作的Prolog术语扩展机制将DCG规则扩展为普通的Prolog规则.
例如,使用expand_term / 2:
?- expand_term((expr(A,symbol(B)),Clause). Clause = (expr(A,[' ',i,s,' ',g,r,e|...],B,_G242,_G253):-symbol(A,_G264),_G264=[' ',g|...],symbol(B,_G275,_G253)).
你可以用assertz / 1断言这样的子句:
?- expand_term((Head --> Body),Clause),assertz(Clause).
请注意,我在此示例中使用double_quotes设置为chars,即使用:
:- set_prolog_flag(double_quotes,chars).
在您的源文件中.无论如何,这是一个好主意.
另请注意,我假设您已经找到了将您在generate_dcg_rule / 1示例中提供的列表转换为实际DCG的方法.对于这个翻译,我宁愿推荐像list_dcg / 2那样的谓词,它以声明的方式描述这些列表和DCG规则之间的关系.优点很明显:例如,您可以交互式地测试这种关系以及测试用例等.对于您的具体示例,定义此关系的一个子句可以类似于:
list_dcg([A,Ls,B],DCG) :- Ls = "is greater than ",DCG = (expr(A,B) --> symbol(A),symbol(B)).
我将此概括为您的其他用例作为练习.总的来说,动态断言这些子句的一种方法是:
?- list_dcg(List,DCG),expand_term(DCG,assertz(Clause).
请注意我们在这些例子中如何从Prolog的同性化特性中受益:Prolog规则和DCG规则具有Prolog术语的自然表示,我们可以简单地将它们写下来并像在目标内的任何其他术语一样推理它们.