我正在尝试制作一个包含两个数字K的谓词,Num(使用谓词时为0,每次递归后都会更改),一个包含数字从1到K的列表,以及一个所有键从1到K的关联树K的值为0。在列表中找到从1到K的所有数字(Num直到此为止都找到数字)时,它返回列表NL的其余部分和一个关联树,其中每个键的值是每个数字乘以找到了。应该这样使用:
first(3, 0, [1,3,1,3,1,3,3,2,2,1], T, NL, NT)
其中T是上述树。
这是我的代码:
first(K, K, L, T, L, T):- !.
first(_, _, [], _, [], NT) :-
empty_assoc(NT), !.
first(K, Num, [H|L], T, NL, NT) :-
get_assoc(H, T, V),
Newv is V+1,
put_assoc(H, T, Newv, TT),
V=:=0 -> Newnum is Num+1; Newnum is Num,
first(K, Newnum, L, TT, NL, NT).
我的问题是它返回true而不是NL和NT的值。
答案 0 :(得分:1)
这里的主要问题是运算符优先级。如果我们要求解释器生成listing.
,则会得到:
first(A, A, B, C, B, C) :- !.
first(_, _, [], _, [], A) :-
empty_assoc(A), !.
first(G, E, [A|H], B, I, J) :-
( get_assoc(A, B, C),
D is C+1,
put_assoc(A, B, D, _),
C=:=0
-> F is E+1
; F is E,
first(G, F, H, _, I, J)
).
这可以使我们了解到,只有在C =:= 0
不成立的情况下,我们才会对first/6
进行递归调用。这可能不是您的意图。由于我们仅在条件不成立的情况下进行递归调用,因此TT
如果我们使用方括号,例如:
first(K, K, L, T, L, T):- !.
first(_, _, [], _, [], NT) :-
empty_assoc(NT), !.
first(K, Num, [H|L], T, NL, NT) :-
get_assoc(H, T, V),
Newv is V+1,
put_assoc(H, T, Newv, TT),
(V=:=0 -> Newnum is Num+1; Newnum is Num),
first(K, Newnum, L, TT, NL, NT).
在修复了该错误之后,我们得到一个错误:
?- first(3, 0, [1,3,1,3,1,3,3,2,2,1], T, NL, NT)
| .
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [13] throw(error(instantiation_error,_7048))
ERROR: [9] assoc:get_assoc(1,_7080,_7082) at /usr/lib/swi-prolog/library/assoc.pl:178
ERROR: [8] first(3,0,[1,3|...],_7112,_7114,_7116) at /tmptest.pl:5
ERROR: [7] <user>
这意味着我们的目标是调用get_assoc/3
,但要使用非构造的关联数组。请注意,empty_assoc/1
不是构造的,它仅在列表用尽时才构造。
我认为这里的核心问题是您一次做太多事情。我们可以做一些小的谓词,每个谓词只能做有限的工作。
例如,我们可以生成一个关联数组,该数组将1
和K
之间的所有值映射为0
:
gen_assoc(K, A) :-
empty_assoc(E),
gen_assoc(K, E, A).
gen_assoc(0, A, A).
gen_assoc(K, A, C) :-
K > 0,
put_assoc(K, A, 0, B),
K1 is K-1,
gen_assoc(K1, B, C).
因此,gen_assoc(3, A)
将通过一个关联数组统一A
,该数组将1
到3
(包括两端)的所有数字映射到0
。 >
我把剩下的作为练习。