合并生成器结果并将结果写入流 [英] Combing generator results and writing result to stream

查看:16
本文介绍了合并生成器结果并将结果写入流的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前我可以生成表达式树.

expression_tree([_|N_s],N_s, [number(0)]).表达式树([_|N_s0],N_s1,[op(neg),[E1]]):-表达式树(N_s0,N_s1,E1).表达式树([_|N_s0],N_s2, [op(add), [E1, E2]]) :-表达式树(N_s0,N_s1,E1),表达式树(N_s1,N_s2,E2).生成表达式(N_c,E):-长度(N,N_c),表达式树(N,[],E).?- 生成表达式(N,E).N = 1,E = [数字(0)];N = 2,E = [op(neg), [[number(0)]]] ;N = 3,E = [op(neg), [[op(neg), [[number(0)]]]]] ;N = 3,E = [op(add), [[number(0)], [number(0)]]] ;N = 4,E = [op(neg), [[op(neg), [[op(neg), [[number(0)]]]]]]] ;N = 4,E = [op(neg), [[op(add), [[number(0)], [number(0)]]]]] ;N = 4,E = [op(add), [[number(0)], [op(neg), [[number(0)]]]]];N = 4,E = [op(add), [[op(neg), [[number(0)]]], [number(0)]]] ;N = 5,E = [op(neg), [[op(neg), [[op(neg), [[op(neg), [[number(0)]]]]]]]]]

其中 N 是树的节点数.

我也可以独立生成序列号.

sequence_number(Sequence_number) :-序列号(1,序列号).序列号(我,我).序列号(I,K):-J 是 I + 1,序列号(J​​,K).?- 序列号(N).N = 1 ;N = 2;N = 3 ;N = 4;N = 5 ;N = 6

我也可以生成和输出表达式,但序列号不正确

print_expression(Stream, Prefix, Suffix, Sequence_number, E) :-写(流,前缀),格式(流,'~|~`0t~d~7+',序列号),写(流,,"),写(流,E),写(流,后缀),nl(流).print_expressions_a(Stream, Prefix, Suffix, Sequence_number, N) :-生成表达式(N,E),print_expression(Stream, Prefix, Suffix, Sequence_number, E).print_expressions_a :-流 = 用户输出,前缀 = '(',后缀 = ')',序列号 = 1,N = 4,print_expressions_a(流,前缀,后缀,序列号,N).


?- print_expressions_a.(0000001, [op(neg),[[op(neg),[[op(neg),[[number(0)]]]]]]])真的 ;(0000001, [op(neg),[[op(add),[[number(0)],[number(0)]]]]])真的 ;(0000001, [op(add),[[number(0)],[op(neg),[[number(0)]]]]])真的 ;(0000001, [op(add),[[op(neg),[[number(0)]]],[number(0)]]])真的 ;错误的.

注意序列号都是0000001.

这是生成选择点,所以我使用 forall

对其进行了修改

print_expressions_b(Stream, Prefix, Suffix, Sequence_number, N) :-对所有人(生成表达式(N,E),print_expression(Stream, Prefix, Suffix, Sequence_number, E)).print_expressions_b :-流 = 用户输出,前缀 = '(',后缀 = ')',序列号 = 1,N = 4,print_expressions_b(流,前缀,后缀,序列号,N).?- print_expressions_b.(0000001, [op(neg),[[op(neg),[[op(neg),[[number(0)]]]]]]])(0000001, [op(neg),[[op(add),[[number(0)],[number(0)]]]]])(0000001, [op(add),[[number(0)],[op(neg),[[number(0)]]]]])(0000001, [op(add),[[op(neg),[[number(0)]]],[number(0)]]])真的.

这仍然是错误的.

<小时>

我寻求的输出是

(0000001, [op(neg),[[op(neg),[[op(neg),[[number(0)]]]]]]])(0000002, [op(neg),[[op(add),[[number(0)],[number(0)]]]]])(0000003, [op(add),[[number(0)],[op(neg),[[number(0)]]]]])(0000004, [op(add),[[op(neg),[[number(0)]]],[number(0)]]])

其中每个序列号都是唯一的,并且从 01 开始是连续的,并且可以写入文件.对于此示例,流设置为 user_output 以简化问题.

如果我将序列号生成器添加到混合中

print_expressions_c(Stream, Prefix, Suffix, N) :-生成表达式(N,E),序列号(序列号),print_expression(Stream, Prefix, Suffix, Sequence_number, E).print_expressions_c :-流 = 用户输出,前缀 = '(',后缀 = ')',N = 4,print_expressions_c(流,前缀,后缀,N).?- print_expressions_c.(0000001, [op(neg),[[op(neg),[[op(neg),[[number(0)]]]]]]])真的 ;(0000002, [op(neg),[[op(neg),[[op(neg),[[number(0)]]]]]]])真的 ;(0000003, [op(neg),[[op(neg),[[op(neg),[[number(0)]]]]]]])真的 ;(0000004, [op(neg),[[op(neg),[[op(neg),[[number(0)]]]]]]])真的 ;(0000005, [op(neg),[[op(neg),[[op(neg),[[number(0)]]]]]]])真的 ;

序列号现在是正确的,但是永远不会生成新的表达式,因为序列号生成器正在使用选择点来生成下一个序列号,因此谓词 sequence_number 不会回溯到generate_expression 谓词获取新表达式.

那么,我可以使用两个连续依赖回溯的生成器吗?如果有,怎么做?

补充

这与我之前关于树生成器的问题有关.
我知道这应该通过 来完成,并且应该更改数据结构,但是当我试图理解这一点时,以这种方式看待它更容易理解.

相关的 SO 问题

解决方案

收回回溯

总结问题,你想:

  • 使用迭代深化的生成器生成表达式
  • 数字每个解都带有连续的整数.

因此,您面临的核心问题是保留信息而不是回溯.

这在纯 Prolog 中当然不可能:这样做会破坏我们期望从关系中得到的最基本的属性,特别是我们期望回溯撤消 在当前计算分支中发生的一切.

因此,一个纯粹的解决方案是消除回溯

我不是在开玩笑:我们现在将更改对解决方案的整个搜索,使每个解决方案都不回溯,即使程序看起来像 ifem> 它使用了回溯.事实上,该程序甚至会保持不变,但我们对它的解释与普通 Prolog 的解释不同.这种策略允许我们随身携带一个计数器,并为我们找到的每个解决方案配备连续整数.

本质上,我现在是在inin Prolog 中实现回溯,也就是说,我正在使用 Prolog 内置的回溯机制来实现回溯without,这样我就可以自由地根据需要扩展它.

具体化回溯

<块引用>

to reify = 使其成为事物"(来自拉丁语:res, rei f. = 物质、事物、事件)

首先,我将用不同的方式表示整个程序,以便更容易推理.我将使用的表示避免常规 Prolog 目标的默认表示,而是使用目标的列表.我会将每个子句表示为以下形式的事实:

<上一页>head_body(Head, [Goal1,Goal2,...,Goaln]).

此更改纯粹是语法上的(尽管它极大地有助于我们程序中的进一步处理),并且可以轻松自动化:

<上一页>head_body(表达式树([_|N_s],N_s, [number(0)]), []).head_body(表达式树([_|N_s0],N_s1, [op(neg),[E1]]),[表达式树(N_s0,N_s1,E1)]).head_body(表达式树([_|N_s0],N_s2, [op(add), [E1, E2]]),[表达式树(N_s0,N_s1,E1),表达式树(N_s1,N_s2,E2)]).

我们可以使用 元解释器解释这个程序,如下所示:

<上一页>米([G-[]|_],G).米([Gs0|休息],G):-findall(G0-Body, (Gs0 = G0-[First|Others],head_body(First, Body0),append(Body0, Others, Body)), Nexts, Rest),米(下一个,G).

注意,这个解释器在搜索解决方案时不再发生回溯,除了收集所有匹配的子句,实际上报告任何解决方案,这只是接口的一部分,而不是核心 逻辑.

还请注意,append/3 调用可以通过使用子句表示中的列表差异消除.我把它作为一个非常简单的练习.

要使用这个解释器,我们将主要谓词更改为:

<上一页>生成表达式(N_c,E):-长度(N,N_c),mi([E-[表达式树(N,[],E)]], E).

示例查询:

<上一页>?- 生成表达式(N,E).N = 1,E = [数字(0)];N = 2,E = [op(neg), [[number(0)]]] ;N = 3,E = [op(neg), [[op(neg), [[number(0)]]]]] ;N = 3,E = [op(add), [[number(0)], [number(0)]]] ;N = 4,E = [op(neg), [[op(neg), [[op(neg), [[number(0)]]]]]]].

这与您已有的等效,因此目前没有多大帮助.顺便说一句,也许现在是摆脱这种我们有足够的括号了吗"符号的好时机,这样未来的解决方案就更容易阅读了.例如,考虑以 op_arguments/2 形式的术语来表示表达式,或者更好但更简单的 Prolog 术语,形式为 (+)/2 等.

枚举解决方案

现在回到重点:使用元解释器的主要优势在于它让我们改变普通 Prolog 执行此类程序的方式.

在我们的例子中,现在是时候为解决方案引入一个计数器了.我们的第一次尝试可能如下所示:

<上一页>mi(Alts0, S0, S, G) :-( Alts0 = [G0-[]|休息] ->( S #= S0,G = G0;S1 #= S0 + 1,mi(休息,S1,S,G));Alts0 = [Gs0|Rest],findall(G0-Body, ( Gs0 = G0-[First|Others],head_body(First, Body0),append(Body0, Others, Body)), Alts, Rest),英里(Alts,S0,S,G)).

调用谓词如下所示:

<上一页>生成表达式(N_c,S,E):-长度(N,N_c),mi([E-[表达式树(N,[],E)]], 0, S, E).

几乎解决了问题,但我们仍然遇到以下问题:

<上一页>?- generate_expression(_, S, _).S = 0 ;S = 0 ;S = 0 ;S = 1 ;S = 0 ;S = 1 ;S = 2 ;S = 3 ;S = 0 ;S = 1 ;S = 2 ;S = 3 ;S = 4;S = 5 ;S = 6 ;S = 7 ;S = 8 ;S = 0 ;S = 1.

所以,解决方案被枚举,但有仍然回溯:回溯发生在 length/2 中,并且对于正在尝试的每个新长度,计数器是 重置.

从一开始就公平

因此,我们现在更改解释器以从一开始就实施公平的计算策略.公平,我们的意思是每个存在的解决方案最终都会 找到.

迭代深化就是这样一种策略.我将此作为练习,并在此示例中实现广度优先 搜索.获得广度优先搜索很容易:我们只需追加新的替代方案.事实上,既然我们现在要实现公平作为解释器的基本属性,我们也可以简化程序来阅读:

<上一页>头体(表达式树([编号(0)]),[]).头体(表达式树([op(否定),[E1]]),[表达式树(E1)]).head_body(表达式树([op(add), [E1, E2]]),[表达式树(E1),表达式树(E2)]).

一个公平的元解释器,实现广度优先搜索枚举解决方案:

<上一页>mi(Alts0, S0, S, G) :-( Alts0 = [G0-[]|休息] ->( S #= S0,G = G0;S1 #= S0 + 1,mi(休息,S1,S,G));Alts0 = [Gs0|Rest],findall(G0-Body, ( Gs0 = G0-[First|Others],head_body(First, Body0),附加(Body0,其他,Body)),Alts1),追加(休息,Alts1,Alts),英里(Alts,S0,S,G)).

我们的主要谓词:

<上一页>生成表达式(S,E):-mi([E-[表达式树(E)]], 0, S, E).

我们开始吧:

<上一页>?- 生成表达式(S,E).S = 0,E = [数字(0)];S = 1,E = [op(neg), [[number(0)]]] ;S = 2,E = [op(neg), [[op(neg), [[number(0)]]]]] ;S = 3,E = [op(add), [[number(0)], [number(0)]]] ;S = 4,E = [op(neg), [[op(neg), [[op(neg), [[...]]]]]]] ;S = 5,E = [op(neg), [[op(add), [[number(0)], [number(0)]]]]] ;S = 6,E = [op(add), [[number(0)], [op(neg), [[number(0)]]]]];S = 7,E = [op(add), [[op(neg), [[number(0)]]], [number(0)]]].

保持纯洁!

使用这种方法来解决问题让我们有希望将其推广到其他组合器,因为不同的问题可以相对孤立地解决,并且原始程序可以保持它们的方式 是.

还要注意,我让 toplevel 进行打印.如有必要,我总是可以在任何我想使用不纯谓词的地方编写这些解决方案,但最重要的是,每个解决方案都可以作为一个谓词参数,我实际上可以在 within Prolog 中进行推理.

Currently I can generate expression trees.

expression_tree([_|N_s],N_s, [number(0)]).
expression_tree([_|N_s0],N_s1, [op(neg),[E1]]) :-
    expression_tree(N_s0,N_s1, E1).
expression_tree([_|N_s0],N_s2, [op(add), [E1, E2]]) :-
    expression_tree(N_s0,N_s1, E1),
    expression_tree(N_s1,N_s2, E2).

generate_expression(N_c, E) :-
    length(N, N_c),
    expression_tree(N,[], E).

?- generate_expression(N,E).
N = 1,
E = [number(0)] ;
N = 2,
E = [op(neg), [[number(0)]]] ;
N = 3,
E = [op(neg), [[op(neg), [[number(0)]]]]] ;
N = 3,
E = [op(add), [[number(0)], [number(0)]]] ;
N = 4,
E = [op(neg), [[op(neg), [[op(neg), [[number(0)]]]]]]] ;
N = 4,
E = [op(neg), [[op(add), [[number(0)], [number(0)]]]]] ;
N = 4,
E = [op(add), [[number(0)], [op(neg), [[number(0)]]]]] ;
N = 4,
E = [op(add), [[op(neg), [[number(0)]]], [number(0)]]] ;
N = 5,
E = [op(neg), [[op(neg), [[op(neg), [[op(neg), [[number(0)]]]]]]]]]

where N is the number of nodes for the tree.

I can also independently generate sequence numbers.

sequence_number(Sequence_number) :-
    sequence_numbers(1, Sequence_number).

sequence_numbers(I, I).
sequence_numbers(I, K) :-
    J is I + 1,
    sequence_numbers(J, K).

?- sequence_number(N).
N = 1 ;
N = 2 ;
N = 3 ;
N = 4 ;
N = 5 ;
N = 6 

I can also generate and output the expressions but not with the correct sequence numbers

print_expression(Stream, Prefix, Suffix, Sequence_number, E) :-
    write(Stream,Prefix),
    format(Stream, '~|~`0t~d~7+', Sequence_number),
    write(Stream,", "),
    write(Stream,E),
    write(Stream,Suffix),
    nl(Stream).

print_expressions_a(Stream, Prefix, Suffix, Sequence_number, N) :-
    generate_expression(N, E),
    print_expression(Stream, Prefix, Suffix, Sequence_number, E).

print_expressions_a :-
    Stream = user_output,
    Prefix = '(',
    Suffix = ')',
    Sequence_number = 1,
    N = 4,
    print_expressions_a(Stream, Prefix, Suffix, Sequence_number, N).


?- print_expressions_a.
(0000001, [op(neg),[[op(neg),[[op(neg),[[number(0)]]]]]]])
true ;
(0000001, [op(neg),[[op(add),[[number(0)],[number(0)]]]]])
true ;
(0000001, [op(add),[[number(0)],[op(neg),[[number(0)]]]]])
true ;
(0000001, [op(add),[[op(neg),[[number(0)]]],[number(0)]]])
true ;
false.

Notice the sequence numbers are all 0000001.

Which is generating choice-points, so I modified it using forall

print_expressions_b(Stream, Prefix, Suffix, Sequence_number, N) :-
    forall(
        generate_expression(N, E),
        print_expression(Stream, Prefix, Suffix, Sequence_number, E)
    ).

print_expressions_b :-
    Stream = user_output,
    Prefix = '(',
    Suffix = ')',
    Sequence_number = 1,
    N = 4,
    print_expressions_b(Stream, Prefix, Suffix, Sequence_number, N).

?- print_expressions_b.
(0000001, [op(neg),[[op(neg),[[op(neg),[[number(0)]]]]]]])
(0000001, [op(neg),[[op(add),[[number(0)],[number(0)]]]]])
(0000001, [op(add),[[number(0)],[op(neg),[[number(0)]]]]])
(0000001, [op(add),[[op(neg),[[number(0)]]],[number(0)]]])
true.

which is still wrong.


The output I seek is

(0000001, [op(neg),[[op(neg),[[op(neg),[[number(0)]]]]]]])
(0000002, [op(neg),[[op(add),[[number(0)],[number(0)]]]]])
(0000003, [op(add),[[number(0)],[op(neg),[[number(0)]]]]])
(0000004, [op(add),[[op(neg),[[number(0)]]],[number(0)]]])

Where each sequence number is unique and sequential starting from 0 or 1 and can be written to a file. For this example the stream is set to user_output to simplify the question.

If I add the sequence number generator into the mix

print_expressions_c(Stream, Prefix, Suffix, N) :-
    generate_expression(N, E),
    sequence_number(Sequence_number),
    print_expression(Stream, Prefix, Suffix, Sequence_number, E).

print_expressions_c :-
    Stream = user_output,
    Prefix = '(',
    Suffix = ')',
    N = 4,
    print_expressions_c(Stream, Prefix, Suffix, N).

?- print_expressions_c.
(0000001, [op(neg),[[op(neg),[[op(neg),[[number(0)]]]]]]])
true ;
(0000002, [op(neg),[[op(neg),[[op(neg),[[number(0)]]]]]]])
true ;
(0000003, [op(neg),[[op(neg),[[op(neg),[[number(0)]]]]]]])
true ;
(0000004, [op(neg),[[op(neg),[[op(neg),[[number(0)]]]]]]])
true ;
(0000005, [op(neg),[[op(neg),[[op(neg),[[number(0)]]]]]]])
true ;

the sequence numbers are now correct, but new expressions are never generated because the sequence number generator is using a choice point to generate the next sequence number and so the predicate sequence_number, does not backtrack to the generate_expression predicate to get a new expression.

So, can I use two generators that rely on backtracking in succession? If so, how?

Supplement

This is related to my earlier questions on tree generators.
I am aware that this should be done with , and that the data structure should be changed, but while I am trying to understand this, seeing it this way is easier to comprehend.

Related SO Questions

解决方案

Retracting backtracking

To summarize the question, you would like to:

  • generate expressions using a generator that uses iterative deepening
  • number each solution with consecutive integers.

Thus, the core problem you are facing is preserving information over backtracking.

This is of course impossible in pure Prolog: Doing so would destroy the most elementary properties we expect from relations, in particular our expectation that backtracking undoes everything that happened in the current branch of the computation.

A pure solution, therefore, is to eliminate backtracking!

I'm not joking: We will now change the entire search for solutions in such a way that each solution is found without backtracking, even though the program looks as if it used backtracking. In fact, the program will even stay the same, but we interpret it differently than plain Prolog would do it. This strategy allows us to carry a counter with us, and equip each solution we find with consecutive integers.

In essence, I am now implementing backtracking within Prolog, i.e., I am implementing backtracking without using Prolog's built-in mechanism for backtracking, so that I am free to extend it as I want.

Reifying backtracking

to reify = "to make it a thing" (from Latin: res, rei f. = matter, thing, affair)

First, I will represent the whole program differently, so that it easier to reason about it. The representation I shall use avoids the defaulty representation for regular Prolog goals, and instead uses lists of goals. I will represent each clause as a fact of the form:

head_body(Head, [Goal1,Goal2,...,Goaln]).

This change is purely syntactical (even though it helps enormously for further processing within our programs), and can be easily automated:

head_body(expression_tree([_|N_s],N_s, [number(0)]), []).
head_body(expression_tree([_|N_s0],N_s1, [op(neg),[E1]]),
          [expression_tree(N_s0,N_s1, E1)]).
head_body(expression_tree([_|N_s0],N_s2, [op(add), [E1, E2]]),
          [expression_tree(N_s0,N_s1, E1),
           expression_tree(N_s1,N_s2, E2)]).

We can interpret this program with a meta-interpreter like the following:

mi([G-[]|_], G).
mi([Gs0|Rest], G) :-
        findall(G0-Body, (Gs0 = G0-[First|Others],
                          head_body(First, Body0),
                          append(Body0, Others, Body)), Nexts, Rest),
        mi(Nexts, G).

Note that backtracking no longer occurs in this interpreter in the search for solutions, except for collecting all matching clauses, and actually reporting any solutions, which is only part of the interface but not of the core logic.

Note also that the append/3 call can be eliminated by using list differences in the clause representation. I leave this as a very easy exercise.

To use this interpreter, we change our main predicate to read:

generate_expression(N_c, E) :-
        length(N, N_c),
        mi([E-[expression_tree(N,[],E)]], E).

Sample query:

?- generate_expression(N, E).
N = 1,
E = [number(0)] ;
N = 2,
E = [op(neg), [[number(0)]]] ;
N = 3,
E = [op(neg), [[op(neg), [[number(0)]]]]] ;
N = 3,
E = [op(add), [[number(0)], [number(0)]]] ;
N = 4,
E = [op(neg), [[op(neg), [[op(neg), [[number(0)]]]]]]] .

This is equivalent to what you already have, and so it does not help a lot currently. By the way, maybe it is now a good time to get rid of this "have we got enough brackets yet" notation, so that future solutions are a bit easier to read. Consider for example terms of the form op_arguments/2 to represent expressions, or better yet simply Prolog terms of the form (+)/2 etc.

Enumerating solutions

Now back to the main point: The key advantage of using a meta-interpreter is that it lets us change how plain Prolog would execute such programs.

In our case, now is the time to introduce a counter for solutions. Our first attempt could look like this:

mi(Alts0, S0, S, G) :-
        (   Alts0 = [G0-[]|Rest] ->
            (   S #= S0,
                G = G0
            ;   S1 #= S0 + 1,
                mi(Rest, S1, S, G)
            )
        ;   Alts0 = [Gs0|Rest],
            findall(G0-Body, ( Gs0 = G0-[First|Others],
                               head_body(First, Body0),
                               append(Body0, Others, Body)), Alts, Rest),
            mi(Alts, S0, S, G)
        ).

With the invoking predicate looking like this:

generate_expression(N_c, S, E) :-
        length(N, N_c),
        mi([E-[expression_tree(N,[],E)]], 0, S, E).

This almost solves the issue, but we still have the following problem:

?- generate_expression(_, S, _).
S = 0 ;
S = 0 ;
S = 0 ;
S = 1 ;
S = 0 ;
S = 1 ;
S = 2 ;
S = 3 ;
S = 0 ;
S = 1 ;
S = 2 ;
S = 3 ;
S = 4 ;
S = 5 ;
S = 6 ;
S = 7 ;
S = 8 ;
S = 0 ;
S = 1 .

So, solutions are enumerated, but there's still backtracking: The backtracking happens in length/2, and for each new length that is being tried, the counter is reset.

Fair from the start

We therefore now change the interpreter to implement a fair computation strategy right from the start. By fair, we mean that every solution that exists is eventually found.

Iterative deepening is one such strategy. I leave this as an exercise, and implement breadth-first search in this example. Obtaining breadth-first search is easy: We simply append new alternatives. In fact, since we are now about to implement fairness as a fundamental property of the interpreter, we can also simplify the program to read:

head_body(expression_tree([number(0)]), []).
head_body(expression_tree([op(neg), [E1]]),
          [expression_tree(E1)]).
head_body(expression_tree([op(add), [E1, E2]]),
          [expression_tree(E1),expression_tree(E2)]).

A fair meta-interpreter, implementing breadth-first search and enumerating solutions:

mi(Alts0, S0, S, G) :-
        (   Alts0 = [G0-[]|Rest] ->
            (   S #= S0,
                G = G0
            ;   S1 #= S0 + 1,
                mi(Rest, S1, S, G)
            )
        ;   Alts0 = [Gs0|Rest],
            findall(G0-Body, ( Gs0 = G0-[First|Others],
                               head_body(First, Body0),
                               append(Body0, Others, Body)), Alts1),
            append(Rest, Alts1, Alts),
            mi(Alts, S0, S, G)
        ).

Our main predicate:

generate_expression(S, E) :-
        mi([E-[expression_tree(E)]], 0, S, E).

And here we go:

?- generate_expression(S, E).
S = 0,
E = [number(0)] ;
S = 1,
E = [op(neg), [[number(0)]]] ;
S = 2,
E = [op(neg), [[op(neg), [[number(0)]]]]] ;
S = 3,
E = [op(add), [[number(0)], [number(0)]]] ;
S = 4,
E = [op(neg), [[op(neg), [[op(neg), [[...]]]]]]] ;
S = 5,
E = [op(neg), [[op(add), [[number(0)], [number(0)]]]]] ;
S = 6,
E = [op(add), [[number(0)], [op(neg), [[number(0)]]]]] ;
S = 7,
E = [op(add), [[op(neg), [[number(0)]]], [number(0)]]] .

Stay pure folks!

Using this pure approach to solve the issue gives us some hope to generalize this to other combinators, since the different concerns can be addressed in comparative isolation, and the original programs can stay the way they are.

Note also that I let the toplevel do the printing. If necessary, I can always write these solutions anywhere I want using impure predicates, but first and foremost each solution is available as a predicate argument that I can actually reason about within Prolog.

这篇关于合并生成器结果并将结果写入流的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆