来自this answer 上的“方法 3”,在此处进行了完整评论:
在
rosettacode.org,
在 Fibonacci/Prolog 下,以下相当有趣的解决方案是
给定的。它使用一个“惰性列表”,它是一个开放列表(一个列表,其中
终止(“fin”)不是[],而是一个未绑定的变量),其中
使用“冻结目标”附加到列表终止的未绑定变量
谓词
freeze/2。
每当它的值时,都会运行冻结目标(“协程”)
需要未绑定的变量。
使用“惰性列表”作为缓存继续“自下而上”。 “懒人名单”
是一个开放列表,它有一个冻结的目标来计算下一个列表
进入它的“鳍”。
使用nth0(N,Cache,F) 检索列表成员会导致未绑定的“fin”与新列表框[|] 统一。这
解冻“鳍”上的目标,然后计算下一个
斐波那契数,将其与列表框的 arg1 统一起来,然后
在列表框的 arg2 上设置一个新的冻结目标,即
惰性列表的 % 新“fin”。
目前尚不清楚为什么这适用于nth0/3,因此提供了一个替换谓词retrieve/3,它也打印调试消息。
例子:
?- debug(fib_bll).
?- fib_bottomup_lazylist_cache(10,F,Cache).
% At this point, the cache just contains [0,1|_]: [0,1|_28196]
% At K = 0, N = 10, No unfreeze at this point
% At K = 1, N = 10, No unfreeze at this point
% At K = 2, N = 10, Will call unification with a listbox that will unfreeze the goal
% Unfrozen: FA = 0, FB = 1, FIN has been unified to [1|_28628]
% At K = 3, N = 10, Will call unification with a listbox that will unfreeze the goal
% Unfrozen: FA = 1, FB = 1, FIN has been unified to [2|_28910]
% At K = 4, N = 10, Will call unification with a listbox that will unfreeze the goal
% Unfrozen: FA = 1, FB = 2, FIN has been unified to [3|_29192]
% At K = 5, N = 10, Will call unification with a listbox that will unfreeze the goal
% Unfrozen: FA = 2, FB = 3, FIN has been unified to [5|_29474]
% At K = 6, N = 10, Will call unification with a listbox that will unfreeze the goal
% Unfrozen: FA = 3, FB = 5, FIN has been unified to [8|_29756]
% At K = 7, N = 10, Will call unification with a listbox that will unfreeze the goal
% Unfrozen: FA = 5, FB = 8, FIN has been unified to [13|_30038]
% At K = 8, N = 10, Will call unification with a listbox that will unfreeze the goal
% Unfrozen: FA = 8, FB = 13, FIN has been unified to [21|_30320]
% At K = 9, N = 10, Will call unification with a listbox that will unfreeze the goal
% Unfrozen: FA = 13, FB = 21, FIN has been unified to [34|_30602]
% At K = 10, N = 10, Will call unification with a listbox that will unfreeze the goal
% Unfrozen: FA = 21, FB = 34, FIN has been unified to [55|_30884]
% Unfrozen: FA = 21, FB = 34, FIN has been unified to [55|_30884]
% F = 55,
% Cache = [0,1,1,2,3,5,8,13,21,34,55|_31458],
% freeze(_31458,fibonacci_algorithms:bll_frozen(34,55,_31458)).
注意调用retrieve/3,其中K==N,同样的调试
消息发出两次。这是因为
retrieve_3(K,N,[_|More],F) 首先尝试,导致
解冻,但随后由于K<N 而发出回滚,并且
冻结的目标被恢复。第二条
然后尝试retrieve_3(N,N,[F|_],F),导致相同的结果
解冻。 Prolog 中的副作用:很有趣。
这种方法也允许您根据请求扩大缓存。
例如,
这种方法也允许您根据请求扩大缓存。为了
例如,如果我首先想要 fib(10),然后也想要 fib(13),我可以重复使用缓存,延长它:
?-
fibb_bottomup_lazylist_cache(10,Fib10,Cache),nth0(13,Cache,Fib13).
Fib10 = 55,
Cache = [0,1,1,2,3,5,8,13,21,34,55,89,144,233|_55906],
Fib13 = 233,
freeze(_55906,fibonacci_algorithms:bll_frozen(144,233,_55906)).
注意打印出的剩余目标。
% Carve the constants fib(0) and fib(1) out of the code.
const(fib0,0).
const(fib1,1).
% :- debug(fib_bll). % Uncomment to allow debugging printout
fib_bottomup_lazylist_cache(N,F,Cache) :-
const(fib0,F0),
const(fib1,F1),
Cache=[F0,F1|Fin],
freeze(
Fin,
bll_frozen(F0,F1,Fin)),
debug(fib_bll,"At this point, the cache just contains [0,1|_]: ~q",Cache),
% nth0(N,Cache,F).
retrieve(N,Cache,F).
bll_frozen(FA,FB,FIN) :-
FC is FA + FB,
FIN=[FC|NewFIN],
debug(fib_bll,"Unfrozen: FA = ~d, FB = ~d, FIN has been unified to ~q",[FA,FB,FIN]),
freeze(
NewFIN,
bll_frozen(FB,FC,NewFIN)).
% A replacement for nth0/3 to show what's going on
retrieve(N,Cache,F) :-
retrieve_2(0,N,Cache,F).
retrieve_2(K,N,Cache,F) :-
(var(Cache)
-> debug(fib_bll,"At K = ~d, N = ~d, Will call unification with a listbox that will unfreeze the goal",[K,N])
; debug(fib_bll,"At K = ~d, N = ~d, No unfreeze at this point",[K,N])),
retrieve_3(K,N,Cache,F).
retrieve_3(K,N,[_|More],F) :-
K < N,
!,
Kp is K+1,
retrieve_2(Kp,N,More,F).
retrieve_3(N,N,[F|_],F).