3

我无法清楚地理解 cut 的用法。例如在这种情况下:flatten,真的需要吗?即使没有两个切谓词,它也对我有用(我尝试删除)。哪些情况会导致回溯进入cut?删除剪辑后,您对“序言的艺术”(Shapiro E.,Sterling L.)一书具有相同的实现,即:

flatten([X|Xs],Ys) :-
    flatten(X,Ysl), 
    flatten(Xs,Ys2), 
    append(Ys1,Ys2,Ys).
flatten(X,[X]) :- 
    constant(X), 
    X\=[].
flatten([],[]).

这引出了另一个问题:是否有必要在第二个子句中检查它是否不是列表?如果它是一个单独的术语将不会与第一个子句统一......不是吗?

4

1 回答 1

2

您问题中链接的程序使用 cut!运算符来防止答案中的代码与其他子句统一。如果没有这些从答案中删减flatten2/2的内容,第一个参数中的空列表将与第一个和第三个子句统一起来,即

flatten2([], []) :- !.
flatten2(L, [L]).

同样,如果在第二个子句中没有删减,flatten2/2则会在第二个和第三个子句中统一一个非空列表,从而导致不正确的行为。

另一方面,您的代码具有明确的检查,以确保每个子句都flatten/2处理一种特定情况:

  • 第一个子句递归地展平非空列表
  • 第二个子句从空列表以外的常量创建单项列表
  • 第三个子句“扁平化”空列表。

由于每个条款仅适用于左侧的单一类型的项目,因此不需要削减。您可以通过切换第二个和第三个子句并在匹配空列表后添加一个剪切来重写您的代码,但我强烈建议不要这样做(演示)。

是否有必要在第二个子句中检查它是否不是列表?

这个检查是必要的,因为空列表[]被认为是一个常量,所以当空列表出现在被展平的列表中时,你的程序会出现不正确的行为(demo)。

于 2015-09-14T16:06:24.743 回答