如何在没有 DCG 的 L 系统启发的重写系统中进行递归

Posted

技术标签:

【中文标题】如何在没有 DCG 的 L 系统启发的重写系统中进行递归【英文标题】:How to do recursion in a L-system inspired rewrite System, without DCG 【发布时间】:2022-01-07 02:36:12 【问题描述】:

我正在尝试编写一个受 Aristid Lindenmayers L-System 启发的小型递归重写系统,主要是为了学习 Prolog 以及思考 Prolog 中的生成概念。我想在没有 DCG 的情况下实现这一目标。由于最初的 generate.output 谓词有副作用,它不是 100% 纯序言的想法。不要犹豫,把这个概念拆开。

我的主要问题是在列表的末尾。匹配原始列表中每个元素的规则,并使用每次替换的结果创建一个新列表。

[a] Axiom 变为 [a,b] 变为 [a,b,a] 等等。或者更好地作为列表列表 [[a,b],[a]] 让它更灵活、更易于理解,然后再将其展平?

没有常量的基本示例,可以以类似的方式添加。 Axiom 一开始只使用一次。这个想法是将要交换的规则名称或符号以及应该与之交换的符号编码为事实/关系。以generate. 开头将使用计数器重复 20 次。

% The rules
axiom(a, [a]).           
rule(a, [a, b]).
rule(b, [a]). 

% Starts the program
generate :- 
    axiom(a, G), 
    next_generation(20, G).

% repeats it until counter 0. 
next_generation(0, _) :- !. 
next_generation(N, G) :- 
    output(G),                     
    linden(G, Next), 
    succ(N1, N),                           
    next_generation(N1, Next). 

% Concatenates the list to one string for the output
output(G) :- 
    atomic_list_concat(G,'',C),
    writeln(C).

% Here I am stuck, the recursive lookup and exchange. 
% How do I exchange each element with the according substitution to a new list

linden([],[]).             % Empty list returns empty list.
linden([R],Next) :-        % List with just one Element, e.g. the axiom 
   rule(R, Next).          % Lookup the rule and List to exchange the current
linden([H|T], Next) :-     % If more than one Element is in the original list
   rule(H,E),              % match the rule for the current Head/ List element
   % ?????                 % concatenate the result with the result of former elements 
   linden(T, Next).        % recursive until the original list is processed.
                           % Once this is done it returns the nw list to next_generation/2

【问题讨论】:

"没有 DCG" 为什么? DCG 只是一种跳过两个始终相同的参数的方法。几乎所有系统 atm 都使用机械重写;你甚至可以在 DCG 规则上使用listing/1 来查看。这是一个非常奇怪的要求。 我知道,但这是一个练习,因为 DCG 是为了方便,我想了解它是如何工作的。这有什么奇怪的? 【参考方案1】:

是的,您需要列表列表。然后每个字符可以干净地映射到一个对应的扩展列表:

linden([], []).
linden([H|T], [E | Next]) :-
   rule(H, E),
   linden(T, Next).

(顺便说一句,这比使用 DCG 更简单、更短。)

例如:

?- linden([a], Expansion).
Expansion = [[a, b]].

?- linden([a, b, a], Expansion).
Expansion = [[a, b], [a], [a, b]].

然后在扩展下一代之前将其扁平化为扁平列表。

【讨论】:

这是一个不错的解决方案!

以上是关于如何在没有 DCG 的 L 系统启发的重写系统中进行递归的主要内容,如果未能解决你的问题,请参考以下文章

如何在DCG之后从知识库中生成一些短语?

在flutter中进入暗模式时更改系统导航和状态栏的颜色

重写父类方法

使用 DCG 编写简单的“消除过程”Prolog 代码

Prolog DCG中的可选项或重复项

如何获取本机系统调用地址