【问题标题】:Why are solutions in the wrong order?为什么解决方案的顺序错误?
【发布时间】:2023-01-31 03:23:02
【问题描述】:

我被要求

定义一个谓词subseq/2,签名为subseq(-,+), 当它的两个参数都是列表并且它的第一个 可以通过删除零个或多个元素来构造参数 从它的第二个参数。

...具有预期的解决方案顺序:

?- subseq(X, [a, b, c]).
X = [a, b, c] ;
X = [a, b] ;
X = [a, c] ;
X = [a] ;
X = [b, c] ;
X = [b] ;
X = [c] ;
X = [].

我的代码:

subseq([], []).
subseq([], [_|_]).
subseq([X|XS], [X|YS]) :- subseq(XS, YS).
subseq([X|XS], [_|YS]) :- subseq([X|XS], YS).

我的代码的解决顺序:

?- subseq(X, [a, b, c]).
X = []
X = [a]
X = [a, b]
X = [a, b, c]
X = [a, c]
X = [b]
X = [b, c]
X = [c] ;
false.

如何实现预期的解决方案顺序?

【问题讨论】:

    标签: prolog


    【解决方案1】:

    在 Prolog 中,规则的顺序至关重要。要获得所需的输出,只需更改规则的顺序,如下所示:

    subseq([X|XS], [X|YS]) :- subseq(XS, YS).
    subseq([X|XS], [_|YS]) :- subseq([X|XS], YS).
    subseq([], []).
    subseq([], [_|_]).
    
    ?- subseq(X,[a,b,c]).
    X = [a, b, c]
    X = [a, b]
    X = [a, c]
    X = [a]
    X = [b, c]
    X = [b]
    X = [c]
    X = []
    

    【讨论】:

    • 但是,应该注意的是,更改子句的顺序也可能导致意外/意外的行为,尤其是在参数未按预期绑定的情况下。例如,如果 XsYs 都未绑定,则评估 subseq(Xs,Ys). 将导致无限递归。
    【解决方案2】:

    小调整可以改变顺序:

    sub_list_forwards(Sub, Long) :-
        sub_list_forwards_(Long, Sub).
    
    sub_list_forwards_([], []).
    % Either pick H, or don't
    sub_list_forwards_([H|T], S) :-
        (S = Sub ; S = [H|Sub]),
        sub_list_forwards_(T, Sub).
    

    swi-prolog 中的结果:

    ?- sub_list_forwards(S, [a,b,c]).
    S = [] ;
    S = [c] ;
    S = [b] ;
    S = [b, c] ;
    S = [a] ;
    S = [a, c] ;
    S = [a, b] ;
    S = [a, b, c].
    

    或者将选择线调整为:

        (S = [H|Sub] ; S = Sub),
    

    ...这导致您获得的订单:

    ?- sub_list_forwards(S, [a,b,c]).
    S = [a, b, c] ;
    S = [a, b] ;
    S = [a, c] ;
    S = [a] ;
    S = [b, c] ;
    S = [b] ;
    S = [c] ;
    S = [].
    

    请注意,这些都不会留下不需要的选择点最后,因为他们在 [][H|T] 上使用第一个参数索引,每个都有 1 个选择。

    顺序重要吗?最佳顺序是什么?它可能会有所不同。

    一般来说,最好把基本情况(即[], []第一的,为了灵活性(并且因为它们有时包含切割)。

    这是编程,而不是数学,所以有意义的与连续使用 X 和 Y 之类的名称相比,变量名/首字母的可读性要好得多。

    使用 (S = [H|Sub] ; S = Sub), 会产生明智的结果:

    ?- nth1(5, L, e), sub_list_forwards([a,b,c], L).
    L = [a, b, c, _, e] ;
    L = [a, b, c, _, e, _] ;
    L = [a, b, c, _, e, _, _] ;
    L = [a, b, c, _, e, _, _, _] ;
    

    ...而不是堆栈溢出,因此更可取。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-20
      • 2021-11-26
      相关资源
      最近更新 更多