假设我想断言三个列表的长度相同。我可以做这样的事情:
same_length(First, Second, Third) :-
same_length(First, Second),
same_length(Second, Third).
First
当实例化或Second
实例化时,这会做正确的事情。当所有三个参数都被实例化时,它也可以工作!然而,调用 likelength(Third, 3), same_length(First, Second, Third)
会导致它返回带有选择点的正确答案(所有三个列表的长度均为 3),然后永远循环生成永远不会匹配的解决方案。
我写了一个我相信在任何情况下都能做正确事情的版本:
same_length(First, Second, Third) :-
/* naively calling same_length(First, Second), same_length(Second, Third) doesn't work,
because it will fail to terminate in the case where both First and Second are
uninstantiated.
by always giving the first same_length/2 clause a real list we prevent it from
generating infinite solutions */
( is_list(First), same_length(First, Second), same_length(First, Third), !
; is_list(Second), same_length(Second, First), same_length(Second, Third), !
; is_list(Third), same_length(Third, First), same_length(Third, Second), !
% if none of our arguments are instantiated then it's appropriate to not terminate:
; same_length(First, Second), same_length(Second, Third) ).
我一直听说应该尽可能避免切割,这里可以避免吗?
作为一个额外的问题,我认为这些是绿色削减,因为最终谓词是完全相关的,这是真的吗?