这是我在Prolog中的min()
函数,它应该找到数字列表中的最小元素。我的想法是测试Result
是否小于或等于列表中的每个元素。列表的头部将被删除,直到它为空。达到此点时,结果中的设置是正确的。
min([], Result).
min([Head|Tail], Result) :-
Result =< Head,
min(Tail, Result).
在SWI-Prolog中查询此文件时,它可以测试值是否是min([5, 3, 7, 6], 3)
返回true的最小元素。但min([5, 3, 7, 6], X)
找不到X
的值,只返回true
。
如何让它找到X
的值?
答案 0 :(得分:2)
无法设置空列表的最小值。 你可以写
min([X], X).
希望X是一个整数;我认为是! 那么
min([Head|Tail], Result) :-
% you fetch the min of the rest of the list
min(Tail, R1),
(Head < R1
-> Result = Head
; Result = R1).
答案 1 :(得分:2)
我的SWI-Prolog报告
?- min([5, 3, 7, 6], X).
ERROR: user://1:18:
=</2: Arguments are not sufficiently instantiated
这是有道理的,因为第一个X =< 3
是使用未绑定的X
执行的。要使谓词起作用,您需要遵循最小值的定义,该定义未针对空列表定义:
min([X], X).
min([X|L], Min) :-
L = [_|_], % non-empty tail; could be replaced by a cut
min(L, MinL),
Min is min(X, MinL).
(请注意,最后一行会退回到内置min
,由is
进行评估。)
或者,您可以获取元素对的最小值,给出
min([X], X).
min([X,Y|L], Min) :-
MinXY is min(X, Y),
min([MinXY|L], Min).
这个版本是尾递归的。
答案 2 :(得分:2)
如果你打开跟踪,你可以看到你的脚本出了什么问题。
1 ?- trace.
true.
原始版本:
/** Version 0 */
min([], Result).
min([Head|Tail], Result) :-
Result =< Head,
min(Tail, Result).
输出:
[trace] 2 ?- min([5,3,7,6],X).
Call: (6) min([5, 3, 7, 6], _G4129) ? creep
Call: (7) _G4129=<5 ? creep
ERROR: =</2: Arguments are not sufficiently instantiated
Exception: (7) _G4129=<5 ? creep
您试图将未实例化的变量与5进行比较。解决方案:在脚本中交换行,以便在比较之前实例化变量。
/** Version 1 */
min([], Result).
min([Head|Tail], Result) :-
min(Tail, Result),
Result =< Head.
输出:
[trace] 5 ?- min([5,3,7,6],X).
Call: (6) min([5, 3, 7, 6], _G517) ? creep
Call: (7) min([3, 7, 6], _G517) ? creep
Call: (8) min([7, 6], _G517) ? creep
Call: (9) min([6], _G517) ? creep
Call: (10) min([], _G517) ? creep
Exit: (10) min([], _G517) ? creep
Call: (10) _G517=<6 ? creep
ERROR: =</2: Arguments are not sufficiently instantiated
Exception: (10) _G517=<6 ?
[trace] 102 ?- min([5,3,7,6],X).
Call: (6) min([5, 3, 7, 6], _G3067) ? creep
Call: (7) min([3, 7, 6], _G3067) ? creep
Call: (8) min([7, 6], _G3067) ? creep
Call: (9) min([6], _G3067) ? creep
Call: (10) min([], _G3067) ? creep
Exit: (10) min([], _G3067) ? creep
Call: (10) _G3067=<6 ? creep
ERROR: =</2: Arguments are not sufficiently instantiated
Exception: (10) _G3067=<6 ?
这样脚本会更进一步但是当计算尾部的最小值时,它再次与未实例化的变量进行比较。解决方案:将min([], Result).
更改为min([Result], Result)
。
/** version 2 */
min([Result], Result).
min([Head|Tail], Result) :-
min(Tail, Result),
Result =< Head.
输出:
[trace] 8 ?- min([5,3,7,6],3).
Call: (6) min([5, 3, 7, 6], 3) ? creep
Call: (7) min([3, 7, 6], 3) ? creep
Call: (8) min([7, 6], 3) ? creep
Call: (9) min([6], 3) ? creep
Call: (10) min([], 3) ? creep
Fail: (10) min([], 3) ? creep
Fail: (9) min([6], 3) ? creep
Fail: (8) min([7, 6], 3) ? creep
Fail: (7) min([3, 7, 6], 3) ? creep
Fail: (6) min([5, 3, 7, 6], 3) ? creep
false.
该程序现在只返回false。这是因为你只考虑尾部的最小值小于或等于头部的情况。当输入列表按顺序排序时,此程序将仅返回正确的结果(以便尾部的最小值小于头部,递归)。
[trace] 10 ?- min([5,4,3,2],X).
Call: (6) min([5, 4, 3, 2], _G2469) ? creep
Call: (7) min([4, 3, 2], _G2469) ? creep
Call: (8) min([3, 2], _G2469) ? creep
Call: (9) min([2], _G2469) ? creep
Exit: (9) min([2], 2) ? creep
Call: (9) 2=<3 ? creep
Exit: (9) 2=<3 ? creep
Exit: (8) min([3, 2], 2) ? creep
Call: (8) 2=<4 ? creep
Exit: (8) 2=<4 ? creep
Exit: (7) min([4, 3, 2], 2) ? creep
Call: (7) 2=<5 ? creep
Exit: (7) 2=<5 ? creep
Exit: (6) min([5, 4, 3, 2], 2) ? creep
X = 2 .
因此,当尾部的最小值严格大于头部时,你需要通过添加以下条款来处理这种情况:
min([Head|Tail], Result) :-
min(Tail, R1),
Head < R1,
Result is Head.
这是最终版本:
/** version 3 */
min([Result], Result).
min([Head|Tail], Result) :-
min(Tail, Result),
Result =< Head.
min([Head|Tail], Result) :-
min(Tail, R1),
Head < R1,
Result is Head.
(使用nodebug.
转换跟踪)
答案 3 :(得分:1)
它不可能在那里返回true
。 X =< 3
会导致“ERROR: =</2: Arguments are not sufficiently instantiated
”。也许您使用@=<
进行比较,但只需成功X @=< 3
就可以成功,而无需以任何方式实例化X
。因此,X
将保持不变,min([], X)
最终会成功 - 正是您所观察到的。
你的代码也是另一种错误。 min([5, 3, 7, 6], 0)
也取得了成功,但不应该成功。
其他人为您提供了递归解决方案。对于迭代的,我们通常会添加另一个accumulating参数,并将链中的Result
传递给我们,以便从累加器中为我们接收最终值:
min([H|T], Result):- min(T,H,Result).
min([], Result, Result).
min([Head|Tail], M, Result) :-
M =< Head -> min(Tail, M, Result)
; min(Tail, Head, Result).
空列表没有最小值。参数列表的头部用作最小值的初始值。