【问题标题】:Predicate about a list of lists关于列表列表的谓词
【发布时间】:2017-05-03 07:09:59
【问题描述】:

我正在尝试创建一个谓词,它接收列表列表并返回一个列表列表,其中包含来自第一个列表的所有单一列表(长度为 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]], [])

目前每次都在调假

【问题讨论】:

  • 请举例说明它所采用的输入类型,并更准确地说明不正确的输入。
  • 先问:elimina_listas_nao_unitarias_lista_de_listas(T, N)应该真的有答案了!

标签: prolog


【解决方案1】:

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

   ?- length([A], 1).

true

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

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

第二条规则头部的第一个列表及其第一个目标也是如此。在您的第二个目标中,您尝试将 [H|N_List_T] 评估为带有 is/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

编辑:正如 cmets 中的 @false 所指出的,第三条规则中 length/2 和 dif/2 的组合使用不会因 [_,_|_] 而终止,因此查询

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

也不会终止。但是,在这种情况下期望终止是合理的,因为以两个元素为首的列表肯定不能是单一的。因此,您可以考虑描述涵盖所有可能性的四种情况,而不是使用 length/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]]

【讨论】:

  • length(L,X), dif(X,1) 不会为 L = [_,_|_] 终止,但关系可能会终止
  • @false:感谢您指出,我什至没有考虑过这种情况。我相应地更新了我的帖子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-26
  • 1970-01-01
  • 2011-01-05
相关资源
最近更新 更多