我想通过Prolog中的problem解决以下动态编程corecursion。但是我坚持以递归的方式进行广度优先的搜索,我想实现该搜索:
有一个n层的建筑物,其中的电梯只能 一次上升2层,一次下降3层。使用 动态编程编写一个函数来计算 电梯从楼层到达的步数 我到j楼。
我已经决定要使用惰性列表表示形式。懒惰列表只是Prolog闭包C,可以调用它来产生头部和尾部的新闭包。
示例一连串的流:
one(1, one).
然后可以将Haskell take谓词简单地编码如下:
take(0, _, L) :- !, L = [].
take(N, C, [X|L]) :- N > 0,
call(C, X, D),
M is N-1,
take(M, D, L).
这是一个示例运行:
?- take(5, one, X).
X = [1, 1, 1, 1, 1].
?- take(10, one, X).
X = [1, 1, 1, 1, 1, 1, 1, 1, 1|...].
答案 0 :(得分:1)
在此共同递归的序言solution中,我们需要两个构件。
一个构建块是一种在Prolog中联合递归枚举搜索树的方法。我们采用这样的想法,即Prolog闭包术语应带有议程,并带有路径,因此应该扩展节点。然后,我们可以从仅包含根的议程开始:
% tree(-Path, -LazyPaths)
tree(H, T) :-
tree([[]], H, T).
要存档广度优先枚举,我们将在议程末尾附加新的扩展路径和节点。这可以通过简单的列表附加谓词调用来完成,因此缺少的定义如下。在完整的二叉树路径中,因此节点总是被扩展两次:
% tree(+Paths, -Path, -LazyPaths)
tree([X|Y], X, tree(Z)) :-
append(Y, [[0|X],[1|X]], Z).
这是一个示例运行:
?- take(5, tree, L).
L = [[],[0],[1],[0,0],[1,0]]
?- take(10, tree, L).
L = [[],[0],[1],[0,0],[1,0],[0,1],[1,1],[0,0,0],[1,0,0],[0,1,0]]
在评估程序出现问题的情况下,我们将有一条路径,从而使节点扩展不会总是导致两个后继者。如果我们处于k层,则仅当电梯停留在建筑物内部时,电梯才能进入k + 2或k-3层。因此,我们很容易地得出了一个共递归谓词步骤,该步骤确实模拟了电梯的所有可能路径:
?- take(5, steps(7,[[2]]), L).
L = [[2],[4,2],[1,4,2],[6,4,2],[3,1,4,2]]
?- take(10, steps(7,[[2]]), L).
L = [[2],[4,2],[1,4,2],[6,4,2],[3,1,4,2],[3,6,4,2],
[5,3,1,4,2],[5,3,6,4,2],[2,5,3,1,4,2],[7,5,3,1,4,2]]
最后一个障碍和第二个构建块是在Prolog中获得Haskell drop。我们的目标不是针对布尔条件使用Prolog闭包项参数的谓词,而是仅提供枚举惰性列表元素的谓词,并且该谓词的用户可以在Prolog延续中进行过滤。
% drop_while(+LazyList, -Element)
drop_while(C, P) :-
call(C, Q, T),
(P = Q; drop_while(T, P)).
如果将所有内容放在一起,我们将获得一个可追溯的Prolog解决方案,该解决方案甚至可以通过回溯来枚举评估者问题的所有无限解决方案,除了以广度优先顺序计算结果之外,还可以:
?- elevator(7,2,6,L), length(L,N).
L = [6,4,2],
N = 3 ;
L = [6,4,2,5,3,1,4,2],
N = 8 ;
L = [6,4,7,5,3,1,4,2],
N = 8