我需要编写一个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)
你能解释一下我在这里做错了吗?
这是一个实现与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)
小智 1
显而易见的解决方案是:
take(List, N, Prefix) :-
length(List, Len),
( Len =< N
-> Prefix = List
; length(Prefix, N),
append(Prefix, _, List)
).
Run Code Online (Sandbox Code Playgroud)
思考越少,犯错误的机会就越少。它还使谓词更加一般化。