Prolog:拿第一个" N"列表的元素

时间:2014-11-26 14:11:23

标签: list prolog

我需要编写一个Prolog谓词take(L, N, L1),如果列表L1包含列表N的第一个L元素,则会以相同的顺序成功。例如:

?- take([5,1,2,7], 3, L1).
L1 = [5,1,2]
?- take([5,1,2,7], 10, L1).
L1 = [5,1,2,7] 
到目前为止,Prolog对我来说没什么意义,而且我很难将其分解。以下是我到目前为止的情况:

take([H|T], 0, []).
take([H|T], N, L1) :-
   take(T, X, L2),
   X is N-1.

你能解释一下我在这里做错了吗?

6 个答案:

答案 0 :(得分:7)

这是一个在Haskell 1 等函数式语言中实现take的关系对应关系的定义。首先,参数顺序应该是不同的,这有利于部分应用。有一个剪切,但只有在内置(=<)/2的错误检查产生instantiation_error之后,参数才会包含变量。

take(N, _, Xs) :- N =< 0, !, N =:= 0, Xs = [].
take(_, [], []).
take(N, [X|Xs], [X|Ys]) :- M is N-1, take(M, Xs, Ys).


| ?- take(2, Xs, Ys).
Xs = [],
Ys = [] ? ;
Xs = [_A],
Ys = [_A] ? ;
Xs = [_A,_B|_C],
Ys = [_A,_B] ? ;
no

注意上面的查询如何读取:

  

如何从Xs获取Ys中的2个元素?

有3种不同的答案。如果Xs为空,那么Ys也是如此。如果Xs是包含一个元素的列表,那么Ys也是如此。如果Xs至少包含2个元素,则这两个元素为Ys


1)唯一的区别是take(-1, Xs,Ys)失败(对于所有Xs, Ys)。最好的方法是发出与domain_error类似的arg(-1,s(1),2) 功能

答案 1 :(得分:3)

findall / 3它有点像瑞士刀&#39; Prolog。我会用这个片段:

take(Src,N,L) :- findall(E, (nth1(I,Src,E), I =< N), L).

答案 2 :(得分:3)

如果实例化正确,则above code by @CapelliC可以工作;如果没有,它可能表现出不稳定的行为:

?- take(Es, 0, Xs).
**LOOPS**                   % trouble: goal does not terminate

?- take([A,_], 1, [x]).          
true.                       % trouble: variable A remains unbound

为防止这种情况,您可以使用 iwhen/2喜欢这样:

take(Src, N, L) :-
   iwhen(ground(N+Src), findall(E, (nth1(I,Src,E), I =< N), L)).

使用SWI-Prolog 8.0.0运行示例查询:

?- take([a,b,c,d,e,f], 3, Ls).
Ls = [a,b,c].

?- take([a,b,c,d,e,f], N, Ls).
ERROR: Arguments are not sufficiently instantiated

?- take(Es, 0, Xs).
ERROR: Arguments are not sufficiently instantiated

?- take([A,_], 1, [x]).
ERROR: Arguments are not sufficiently instantiated

现在更安全!

答案 3 :(得分:1)

显而易见的解决方案是:

take(List, N, Prefix) :-
    length(List, Len),
    (   Len =< N
    ->  Prefix = List
    ;   length(Prefix, N),
        append(Prefix, _, List)
    ).

少思考意味着错误的机会减少。它也使谓词更加通用。

答案 4 :(得分:1)

您的基本情况很好

take([H|T], 0, []).

如果N为1,你也可以说

take([H|T],1,[H]).

但是在递归的情况下,未定义某些变量,例如L2。所以我们可以这样写

take([X|T1],N,[X|T2]):-
N>=0,
N1 is N-1,
take(T1,N1,T2).

在所有情况下,所有变量都是模式匹配的。

答案 5 :(得分:0)

take(L,N,L1):-长度(L1,N),append(L1,_,L)。