【发布时间】:2015-11-25 20:32:33
【问题描述】:
我想在结果列表中添加 N 到 0 个数字。
示例查询
?- add(5,R).
应该返回答案:
R = [5,4,3,2,1,0].
我已经尝试了以下代码,但没有成功。
add(0, 0).
add(N, [R]) :-
N1 is N-1,
add(N1, [R|N]).
【问题讨论】:
我想在结果列表中添加 N 到 0 个数字。
示例查询
?- add(5,R).
应该返回答案:
R = [5,4,3,2,1,0].
我已经尝试了以下代码,但没有成功。
add(0, 0).
add(N, [R]) :-
N1 is N-1,
add(N1, [R|N]).
【问题讨论】:
你离得太近了!
add(0, [0]).
add(N, [N|R]) :-
N > 0,
N1 is N-1,
add(N1, R).
那么,这里有什么不同?
add(0, [0]) 有 [0] 而不是 0 因为你正在构建一个列表,而不是一个整数;否则你会得到看起来相当尴尬的 [5,4,3,2,1|0] 结果。
N > 0 作为守卫,以确保我们不会在遇到基本情况后永远循环爬取负数。
这项工作是在add/2 的第二个子句的头部而不是它的主体中完成的。也就是说,我们的模式是add(N, [N|R]) 而不是add(N, [R])。这是因为该术语将 N 添加到列表的头部,而不是在重复之前添加它。
同样,[R|N] 中有一个简单的反转;这将建立一种倒退的列表。
总而言之,我认为你非常接近。在提示下进行更多的实验可能足以修复它。您是否尝试过使用trace/0?
【讨论】:
我们展示了this answer 的模拟(它处理来自0 的连续整数升序)。
基于equidistant_stride/2我们查询:
让我们重新运行1我们在this previous answer 中进行的运行时测量!
?- between(1,6,E), Nis10^E, garbage_collect, call_time(numlist(0, N, _), T1_in_ms), 垃圾收集, call_time((_Zs = [N|_Z], 长度(_Z, N), equidistant_stride(_Zs, -1)), T2_in_ms)。 N = 10,T1_in_ms = 0,T2_in_ms = 0 ; N = 100,T1_in_ms = 1,T2_in_ms = 0 ; N = 1000,T1_in_ms = 1,T2_in_ms = 1 ; N = 10000,T1_in_ms = 3,T2_in_ms = 12 ; N = 100000,T1_in_ms = 14,T2_in_ms = 32 ; N = 1000000,T1_in_ms = 90,T2_in_ms = 280。编辑
此答案的过去修订无意中 sk(r)ewed 运行时测量以支持clpfd。如何?
很简单:reverse/2 的目标跟在 numlist/3 之后,尽管在这种情况下它是无用的。
现在应该会更好:Thx 2 @JanWielemaker 4 报告!
脚注 1: 使用 SWI-Prolog 版本 7.3.11(64 位)。
【讨论】:
reverse/2,您有点作弊。编写一个正确排序的 numlist/3 也同样容易。这就是为什么我省略了时序比较的反向。剩下的就是一个明显的算法和一个声明性规范之间的比较,我们只需要希望约束求解器足够聪明以找到正确的算法。给定一个复杂的搜索问题,首先尝试约束是明智的。然而,一个好的算法是可预测的。
使用clpfd!
:- use_module(library(clpfd))。 :- set_prolog_flag(toplevel_print_anon, 假的)。我们这样定义n_to_0/2:
n_to_0(N,[Z|Zs]) :-
length(Zs,N),
[Z|Zs] ins 0..N,
chain([Z|Zs],#>).
OP 给出的示例查询:
?- n_to_0(5,Zs).
Zs = [5,4,3,2,1,0].
使用n_to_0/2 的最一般查询怎么样?
编辑
@JanWielemaker 指出 n_to_0/2(如上定义)非常慢,尤其是在将其与非 clpfd 对应物进行比较时:
非常感谢您的报告!
自己看...
【讨论】:
transpose_ugraph/2,这是在 transpose/2 冲突首次报告并在 SICStus 中长期解决的 8 年后。
?- stadt(X).(注意“Stadt”是德语“城镇”/“城市”的意思)。其他合适的“第一”查询包括 IMO ?- 1+1 #= 2. 和 ?- X #> 1, X #< 4. 和 ?- X #\= 0. 等等……但绝对不是 ?- use_module(library(clpfd)).。