Prolog 从列表中选择 3

Prolog Choose 3 From List

我已经创建了一个 prolog 程序,它给一个 Number 一个 List 和 Sublist 将生成每个包含 N 项的子列表。有人告诉我这可以通过 1 个事实和 2 个规则来完成。我得到的提示是我选择了第一项,或者我没有选择这让我感到困惑。我有基本情况和第一种情况,但我希望有人能帮助我理解第二种情况。

choose(1, [H], [H]).
choose(N, [H,TL], [H|ST]) :- choose(Less1, TL, ST), Less1 is N-1.

所以我的第三条规则我想选择列表中的第二项

choose(N, [F,S|T], [S|ST]) :- choose(Less1, T, ST), Less1 is N-1.

然而,我的最后一条规则是不平衡的,整体不起作用。非常感谢任何想法!

前两句的思路原则上是正确的。然而:

  • 当必须找到长度为 1 的子列表但原始列表的长度不是 1 时,第一个子句没有用。这是有问题的。
  • 在第二个子句中,我假设你的意思是 [H|TL]。

鉴于这些,您的问题的解决方案可能是:

choose(1, [H|_], [H]).
choose(N, [H|TL], [H|ST]) :- Less1 is N - 1, choose(Less1, TL, ST).
choose(N, [_|T], L) :- choose(N, T, L).

尝试解释:

  • 第一个子句将生成长度为 1 的子列表,给定任何至少包含一个元素的列表:它将简单地将第三个参数与仅包含原始列表头部的单元素列表统一起来。
  • 第二个子句将处理请求长度大于 1 的子列表的情况,在这种情况下,它将第三个参数与包含原始列表的头部和尾部的列表统一,由于递归,将是原始列表尾部的子列表,其长度等于请求的长度减去 1。
  • 第三个子句将简单地跳过原始列表的头部,并将第三个参数与一个列表统一起来,由于递归,该列表将是原始列表尾部的请求长度的子列表。

感谢第三个子句,Prolog 将能够为等于或大于 1 的请求长度提供替代解决方案。

一些结果:

?- choose(2, [1,2,3,4], L).
L = [1, 2] ;
L = [1, 3] ;
L = [1, 4] ;
L = [2, 3] ;
L = [2, 4] ;
L = [3, 4] ;
false.

请注意,您不能像使用 那样使用它来解决具有未绑定长度变量的查询。要在纯 Prolog 中实现这一点,您必须稍微更改第二个子句背后的逻辑:

choose(N, [H|TL], [H|ST]) :- choose(Less1, TL, ST), N is Less1 + 1.

这也可能有助于阐明递归在这种情况下的工作原理。

希望对您有所帮助。

(免责声明:我相当确定可以对上述解决方案的工作原理提供更好的解释(更不用说更好的解决方案了)。)

同时 should already point you in the right direction, we extend on it in this answer by using :

:- use_module(library(clpfd)).

我们这样定义n_from_chosen/3

n_from_chosen(0,_,[]).
n_from_chosen(N,[X|Es],[X|Xs]) :-
   N #> 0,
   N #= N0+1,
   n_from_chosen(N0,Es,Xs).
n_from_chosen(N,[_|Es],Xs) :-
   N #> 0,
   n_from_chosen(N,Es,Xs).

示例查询:

?- n_from_chosen(2,[1,2,3,4],Xs).
  Xs = [1,2]
; Xs = [1,3]
; Xs = [1,4]
; Xs = [2,3]
; Xs = [2,4]
; Xs = [3,4]
; false.

这个更一般的查询怎么样?

?- n_from_chosen(N,[1,2,3],Xs).
  N = 0, Xs = []
; N = 1, Xs = [1]
; N = 2, Xs = [1,2]
; N = 3, Xs = [1,2,3]
; N = 2, Xs = [1,  3]
; N = 1, Xs =   [2  ]
; N = 2, Xs =   [2,3]
; N = 1, Xs =     [3]
; false.