关于列表列表的谓词

时间:2017-05-01 19:10:34

标签: prolog

我试图创建一个接收列表列表的谓词,并从第一个列表中返回包含所有单一列表(长度为1的列表)的列表列表,但它不起作用。这就是我创造的:

elimina_listas_nao_unitarias_lista_de_listas([[A]|T],N_List):-
  length([A], 1),
  N_List is [H|N_List_T],
  elimina_listas_nao_unitarias_lista_de_listas(T, N_List_T).

elimina_listas_nao_unitarias_lista_de_listas([[A]|T], N_List):-
  length([A], X),
  X > 1,
  elimina_listas_nao_unitarias_lista_de_listas(T, N_List2).

这是应该做的:

elimina_listas_nao_unitarias_lista_de_listas([[1,2],[1,2,3],[3]], [3])
elimina_listas_nao_unitarias_lista_de_listas([[1,2],[1,2,3],[3,4,5]], [])

每次都重新调整错误

1 个答案:

答案 0 :(得分:3)

让我们来看看你的第一条规则。第一个目标总是成功,因为您询问具有单个元素的列表是否长度为1.只需在提示符处尝试:

   ?- length([A], 1).

true

相反,您可能希望在第一个列表的头部没有括号的变量(例如[L|Ls]),并确保它是长度为1的列表:

   ?- length(L,1).
L = [_A]

第二个规则头部的第一个列表及其第一个目标也是如此。在您的第二个目标中,您尝试将[H|N_List_T]计算为具有/ 2的算术表达式,以便N_List保存该值。除了这个没有意义的事实,你可以在提示时尝试,看看这个目标不会成功:

   ?- N_List is [H|N_List_T].
     ERROR!!
     TYPE ERROR- string must contain a single character to be evaluated as an arithmetic expression: expected evaluable term, got [_131245|_131246]

相反,您希望统一这两个术语:

   ?- N_List = [H|N_List_T].
N_List = [H|N_List_T]

但是,如果将[H|N_List_T]写为规则头部的第二个参数,则可以完全摆脱这个目标。此外,您可能希望在第二个列表的头部中使用单一列表L而不是变量H。此外,您错过了一个案例,即第一个列表是[]。在这种情况下,第二个列表也是空的,因为空列表显然不包含任何单一列表。最后,我要注意,如果你选择了一个更简单,更具声明性的名称,比如listas_unitarias / 2,它可能会提高代码的可读性。把所有这些放在一起,你最终会得到一个这样的谓词:

listas_unitarias([],[]).
listas_unitarias([L|Ls],[L|Ss]) :-
   length(L,1),
   listas_unitarias(Ls,Ss).
listas_unitarias([L|Ls],Ss) :-
   length(L,X),
   dif(X,1),
   listas_unitarias(Ls,Ss).

您的第二个示例查询会产生所需的结果

   ?- listas_unitarias([[1,2],[1,2,3],[3,4,5]],U).
U = []

对于您的第一个示例查询,结果略有不同:

   ?- listas_unitarias([[1,2],[1,2,3],[3]], U).
U = [[3]] ? ;
no

唯一的单一列表本身就在列表中。这会更有意义,因为第一个参数可能包含多个这样的列表。考虑以下情况:

   ?- listas_unitarias([[1],[2,3],[4],[]],U).
U = [[1],[4]] ? ;
no

但是,如果您打算一次获得一个单一列表,则谓词看起来会略有不同:

listas_unitarias2([L|_Ls],L) :-
   length(L,1).
listas_unitarias2([_L|Ls],U) :-
   listas_unitarias2(Ls,U).

查询结果如下:

   ?- listas_unitarias2([[1,2],[1,2,3],[3]], U).
U = [3] ? ;
no
   ?- listas_unitarias2([[1],[2,3],[4],[]],U).
U = [1] ? ;
U = [4] ? ;
no

特别是你的第二个示例查询:它会失败,而不是将空列表作为解决方案生成:

   ?- listas_unitarias2([[1,2],[1,2,3],[3,4,5]],U).
no
   ?- listas_unitarias2([[1,2],[1,2,3],[3,4,5]],[]).
no

编辑:正如评论中@false指出的那样,第三条规则中长度/ 2和dif / 2的组合使用不会终止[_,_|_]所以查询

   ?- listas_unitarias([[1],[_,_|_],[2],[3,4]],U).
U = [[1],[2]] ? ;
U = [[1],[2]] ? ;
... 

也不会终止。但是,在这种情况下期望终止是合理的,因为以两个元素为首的列表肯定不能单一。因此,您可以考虑描述涵盖所有可能性的四种情况,而不是使用长度/ 2。 1)如果第一个列表为空,那么第二个列表。 2)如果第一个列表的头部是[],则它不在第二个列表中。 3)如果第一个列表的头部是[A],则它在第二个列表中。 4)如果第一个列表的头部至少有两个元素,则它不在第二个列表中。

listas_unitarias([],[]).                    % case 1)
listas_unitarias([[]|Ls],Ss) :-             % case 2)
   listas_unitarias(Ls,Ss).
listas_unitarias([[A]|Ls],[[A]|Ss]) :-      % case 3)
   listas_unitarias(Ls,Ss).
listas_unitarias([[_,_|_]|Ls],Ss) :-        % case 4)
   listas_unitarias(Ls,Ss).

使用此版本,上述查询在找到唯一解决方案后终止:

   ?- listas_unitarias([[1],[_,_|_],[2],[3,4]],U).
U = [[1],[2]]

上面的其他查询产生相同的结果:

   ?- listas_unitarias([[1,2],[1,2,3],[3,4,5]],U).
U = []
   ?- listas_unitarias([[1,2],[1,2,3],[3]], U).
U = [[3]]
   ?- listas_unitarias([[1],[2,3],[4],[]],S).
S = [[1],[4]]