【问题标题】:Simple append problems in PrologProlog 中的简单追加问题
【发布时间】:2014-02-03 08:00:01
【问题描述】:

几周前我一直在研究 Prolog,但我一直坚持的一些琐碎的事情是使用 append 提出解决方案。

例如,如果我有一个类似于

的模式匹配规则
pattern( foo(X,Y), L1, L ) :-
    % some code to go through a list (where the foo-pattern is)
    % and add the pattern to the list L if it matches`

我知道 append/3 是去这里的方式,但是.. L 开始是未知的,即不是地面,当我们开始递归列表时,它开始填充匹配的模式。然而,我总是对最初发生的事情感到困惑,即当 L 不接地时。

例如,这里有一段代码,当第一个参数是可能的模式列表时,我们想要获取所有匹配模式的列表:

pat([foo(X,Y)|L1], R, L) :-  
    append(foo(X,Y),R,L),
    pat(L1, R, [D|L]).
pat([_|L1], R, L2) :-
    pat(L1, R, L2).

非常感谢。

【问题讨论】:

    标签: prolog


    【解决方案1】:

    您可能会选择不使用append/3 的解决方案。例如,考虑以下谓词filter/3

    filter(_Pattern, [], []).
    filter(Pattern, [E|Es], Matches) :-
        Pattern \= E, !,
        filter(Pattern, Es, Matches).
    filter(Pattern, [E|Es], [E|Matches]) :-
        filter(Pattern, Es, Matches).
    

    filter/3 的第一个子句是基本情况,如果在第二个参数列表中没有(左)匹配,那么我们得到一个空列表。由于我们没有考虑Pattern,因此它被忽略(因此前面的_ 与变量相对)。

    filter/3 的第二个子句测试Pattern,它可以绑定到一个术语(例如,foo(X,Y)),是否可以与列表的第一个元素统一匹配,E\= 操作符在其参数无法统一时会成功,所以如果成功了,当我们没有将E 匹配到模式时,可以将其丢弃并继续(注意剪切! 测试后提交到此分支)。

    filter/3 的最后一个(第三个)子句依赖于第二个子句,因为它只是将 E 传递到最后一个参数列表 Matches 上,假设它 与 @ 匹配987654337@,因为前面的子句无法确定它不是匹配项。请注意,我们通过将列表结构绑定到输出而将E 附加到列表中,从而使Matches 子列表未绑定;完整的Matches 列表只有在到达基本情况后才会完全绑定,一旦我们用完第二个参数中的匹配项,就会将其绑定到空列表[],创建类似[E1,E2,...,En|[]] 的东西,其中每个@ 987654343@ 到 En 匹配模式;这个词等同于列表[E1,E2,...,En]

    如下测试这个谓词给出:

    ?- filter(foo(X,Y), [a,b,foo(x,y),c(f),foo(v(3),Z),5], L).
    L = [foo(x, y), foo(v(3), Z)] ;
    false.
    

    请注意,此处与foo(X,Y) 模式一致的所有内容都已根据需要过滤到L

    最后一点:在您的代码中,调用append(foo(X,Y),R,L) 将始终失败,因为append/3 仅对列表进行操作;您可能想改为调用 append([foo(X,Y)],R,L),但在这种情况下,您只需使用 L = [foo(X,Y)|R] 作为简写。

    编辑:为了匹配您有可能匹配和过滤的模式列表的特定情况,这里是另一个谓词filter_list/3

    filter_list(_Patterns, [], []).
    filter_list(Patterns, [E|Es], Matches) :-
        filter(E, Patterns, []), !,
        filter_list(Patterns, Es, Matches).
    filter_list(Patterns, [E|Es], [E|Matches]) :-
        filter_list(Patterns, Es, Matches).
    

    注意filter_list/3 取决于我之前对filter/3 的定义,并且使用完全相同的策略实现:如果E 不匹配任何Patterns(即,@ 987654359@ 成功),然后我们忘记E 并继续,否则(最后一个子句)我们保留它。测试给了我们:

    ?- filter_list([foo(X,Y),bar(X),b], [a,b,foo(X,Y),c], L).
    L = [b, foo(X, Y)] ;
    false.
    

    【讨论】:

      【解决方案2】:

      我不必在您的示例代码中寻找父亲而不是 ... append(foo( ... 标准 append/3 谓词对 lists 进行操作。append(foo(Anything), ...将不匹配它的任何一个子句。因此,您的第一个示例子句应该始终失败,第二个示例子句应该失败或开始构建无限的未绑定变量列表,最终在内存耗尽时爆炸。至于你最终想在这里做,我不是很清楚,但听起来你不想模式匹配,而是在列表中找到与给定术语统一的项目.为什么你认为 append/3 是怎么走?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-13
        • 2020-09-11
        • 2018-01-08
        相关资源
        最近更新 更多