Prolog:获取列表中的第一个"N"元素

Bob*_*ski 7 list prolog

我需要编写一个Prolog谓词take(L, N, L1),如果list L1包含list 的第一个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] 
Run Code Online (Sandbox Code Playgroud)

Prolog到目前为止对我来说没什么意义,而且我很难将其分解.这是我到目前为止:

take([H|T], 0, []).
take([H|T], N, L1) :-
   take(T, X, L2),
   X is N-1.
Run Code Online (Sandbox Code Playgroud)

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

fal*_*lse 7

这是一个实现与takeHaskell 1等函数式语言相关的对应关系的定义.首先,参数顺序应该是不同的,这有利于部分应用.有一个剪切,但只有在内置的错误检查(=<)/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
Run Code Online (Sandbox Code Playgroud)

请注意以上查询如何读取:

一个人怎么可以从2种元素Xs得到Ys

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


1)唯一的区别是take(-1, Xs,Ys)失败(为所有人Xs, Ys).可能最好的是发出domain_error类似的arg(-1,s(1),2)

  • @ScottHunter:是的,确实如此,但这将是一种浪费.我会在使用`#>`时这样做. (3认同)

小智 1

显而易见的解决方案是:

take(List, N, Prefix) :-
    length(List, Len),
    (   Len =< N
    ->  Prefix = List
    ;   length(Prefix, N),
        append(Prefix, _, List)
    ).
Run Code Online (Sandbox Code Playgroud)

思考越少,犯错误的机会就越少。它还使谓词更加一般化。

  • 您当前的解决方案意味着“List”是一个列表,因此长度有限,但如果需要的话,只需要一个前缀。 (5认同)
  • 赫特!这意味着“List”有“N”个元素。但 `List = []` 也应该成功 (4认同)