这个回答是对
先前的回答的直接跟进,特别是针对@WillNess的评论,建议“[...]
交换两个目标,以便在失败时尽快停止遍历 [...]
将chain
放在phrase
之前 [...]”。
lazy_chain/2
类似于
chain/2
,但利用
prolog-coroutining等待足够实例化:
:- use_module(library(clpfd)).
lazy_chain(Zs, R_2) :-
( var(R_2) -> instantiation_error(R_2)
; clpfd:chain_relation(R_2) -> freeze(Zs, lazy_chain_aux(Zs,R_2))
; otherwise -> domain_error(chain_relation, R_2)
).
lazy_chain_aux([], _).
lazy_chain_aux([Z0|Zs], R_2) :-
freeze(Zs, lazy_chain_aux_(Zs,R_2,Z0)).
lazy_chain_aux_([], _, _).
lazy_chain_aux_([Z1|Zs], R_2, Z0) :-
call(R_2, Z0, Z1),
freeze(Zs, lazy_chain_aux_(Zs,R_2,Z1)).
这段代码是关于编程的,使用了Prolog语言中的clpfd库。它定义了一个懒惰链(lazy chain)的谓词,其中包含一些条件判断和递归调用。如果传入的参数不符合要求,则会抛出相应的错误。
基于 lazy_chain/2
,我们定义了这样一个is_bintreeL/2
:
is_bintreeL(T) :-
lazy_chain(Zs, #<),
phrase(in_order(T), Zs).
那么... "早期失败"怎么办?
?- T = node(2, nil, node(1, nil, node(3, nil, node(4, nil, node(5, nil, node(6, nil, node(7, nil, node(8, nil, node(9, nil, node(10, nil, node(11, nil, node(12, nil, node(13, nil, node(14, nil, node(15, nil, node(16, nil, node(17, nil, node(18, nil, node(19, nil, node(20, nil, node(21, nil, node(22, nil, node(23, nil, node(24, nil, node(25, nil, node(26, nil, node(27, nil, node(28, nil, node(29, nil, node(30, nil, node(31, nil, node(32, nil, node(33, nil, node(34, nil, node(35, nil, node(36, nil, node(37, nil, node(38, nil, node(39, nil, node(40, nil, node(41, nil, node(42, nil, node(43, nil, node(44, nil, node(45, nil, node(46, nil, node(47, nil, node(48, nil, node(49, nil, node(50, nil, node(51, nil, node(52, nil, node(53, nil, node(54, nil, node(55, nil, node(56, nil, node(57, nil, node(58, nil, node(59, nil, node(60, nil, node(61, nil, node(62, nil, node(63, nil, node(64, nil, node(65, nil, node(66, nil, node(67, nil, node(68, nil, node(69, nil, node(70, nil, node(71, nil, node(72, nil, node(73, nil, node(74, nil, node(75, nil, node(76, nil, node(77, nil, node(78, nil, node(79, nil, node(80, nil, node(81, nil, node(82, nil, node(83, nil, node(84, nil, node(85, nil, node(86, nil, node(87, nil, node(88, nil, node(89, nil, node(90, nil, node(91, nil, node(92, nil, node(93, nil, node(94, nil, node(95, nil, node(96, nil, node(97, nil, node(98, nil, node(99, nil, node(100, nil, nil)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))),
time((phrase(in_order(T),Zs),eager_chain(Zs,#<))).
% 210 inferences, 0.000 CPU in 0.000 seconds (98% CPU, 4100201 Lips)
false.
?- T = node(2, nil, node(1, nil, node(3, nil, node(4, nil, node(5, nil, node(6, nil, node(7, nil, node(8, nil, node(9, nil, node(10, nil, node(11, nil, node(12, nil, node(13, nil, node(14, nil, node(15, nil, node(16, nil, node(17, nil, node(18, nil, node(19, nil, node(20, nil, node(21, nil, node(22, nil, node(23, nil, node(24, nil, node(25, nil, node(26, nil, node(27, nil, node(28, nil, node(29, nil, node(30, nil, node(31, nil, node(32, nil, node(33, nil, node(34, nil, node(35, nil, node(36, nil, node(37, nil, node(38, nil, node(39, nil, node(40, nil, node(41, nil, node(42, nil, node(43, nil, node(44, nil, node(45, nil, node(46, nil, node(47, nil, node(48, nil
懒惰是胜利者-至少在上述情况下如此:)
但请注意,使用 dcg与lazy_chain/2
可能会导致难以发现的错误!
为了获得更强大的解决方案,请参见this alternative answer...
为了完整起见,这是eager_chain/2
的源代码:
eager_chain(Zs, R_2) :
(var(R_2)-&gt; instantiation_error(R_2)
; clpfd:chain_relation(R_2)-&gt; eager_chain_aux(Zs,R_2)
; 否则 -&gt; domain_error(chain_relation,R_2)
)。
eager_chain_aux([], _)。
eager_chain_aux([Z0 | Zs],R_2):
eager_chain_aux_(Zs,R_2,Z0)。
eager_chain_aux_([], _,_)。
eager_chain_aux_([Z1 | Zs],R_2,Z0):
call(R_2,Z0,Z1),
eager_chain_aux_(Zs,R_2,Z1)。