【问题标题】:Removing heads from lists in Prolog从 Prolog 中的列表中删除头部
【发布时间】:2015-10-02 23:41:44
【问题描述】:

我正在尝试编写一个谓词以从列表列表中的每个列表中删除头部并将尾部添加到新列表中。结果列表应作为第二个参数返回。

这是尝试:

construct_new(S,New) :-
    New = [],
    new_situation(S,New).

new_situation([],_).
new_situation([H|T], New) :-
    chop(H, H1),
    new_situation(T, [H1|New]).

chop([_|T], T).

你可以这样称呼它:

construct_new([[x,x],[b,c],[d,e,f]],S).

然而,这只会产生输出true.

【问题讨论】:

  • 考虑列表之间的关系。以子句new_situation([], _). 为例,这不可能是正确的:您真的希望它为 any 第二个参数保留,例如当前成功的 ?- new_situation([], prolog).?由于您正在描述关系,理想情况下可以在各个方向使用,因此请避免使用“chop”之类的命令性名称。使用更多的声明性名称,如list_without_head/2,以有意义的关系方式描述这两个参数。
  • 忍不住想谓词应该叫queen_of_hearts/2 ...
  • @PauloMoura 太棒了 (+1) :)

标签: list prolog


【解决方案1】:

分步执行

  1. 您的查询是construct_new(Input,Output),对于一些实例化的Input 列表。
  2. construct_new/2 中的第一条语句将Output(又名New)与空列表统一起来。 返回的列表应该在哪里可供调用者使用?两个论点现在统一了。
  3. 您拨打new_situation(Input,[])
  4. 您匹配第二个子句 new_situation([H|T],[]),它递归地执行其任务(第 4 步,...),直到...
  5. 您到达new_situation([],_)成功丢弃了您建立的中间列表。

解决方案

  • 写一个简单的递归谓词:

    new_situation([],[]).
    new_situation([[_|L]|T],[L|R]) :-
        new_situation(T,R).
    
  • 使用maplist:

    construct_new(S,R) :-
        maplist(chop,S,R).
    

备注

正如其他答案和 cmets 所指出的,您的谓词命名错误。 construct_new 不是一个关系,而是一个动作,可以用来表示几乎任何东西。我倾向于喜欢chop,因为它清楚地传达了斩首的行为,但这不是关系的合适名称。 repeatlist_head_tail(L,H,T) 是声明性的,并将变量与其角色相关联。当使用maplist 时,另一个谓词(new_situation)甚至不需要存在...

...虽然guillotine/3很诱人。

【讨论】:

  • 在 Prolog 中实现尾递归通常比在函数式编程语言中更容易。
  • 我建议你踢new_situation/3 并删除你对cmets 答案的引用。然后我们可以“清理” cmets...
  • 尽管很诱人,guillotine/3 并没有表达谓词的关系行为。 ;)
  • @lurker 不幸的是。也许bodies_heads_corpses
  • 是的,我认为是传达关系。
【解决方案2】:

这可以通过 DCG 完成:

owth(Lists, Tails) :-
    phrase(tails(Tails), Lists).

tails([]) --> [].
tails([T|Tails]) --> [[_|T]], tails(Tails).

产生这些查询:

| ?- owth([[x,x],[b,c],[d,e,f]], T).

T = [[x],[c],[e,f]] ? ;

no
| ?- owth(L, [[x],[c],[e,f]]).

L = [[_,x],[_,c],[_,e,f]]

yes

(owth = 他们的脑袋掉了! 或者,如果换个方向,他们的脑袋打开了!)

如果你还想抓人头,可以如下增强:

owth(Lists, Heads, Tails) :-
    phrase(tails(Heads, Tails), Lists).

tails([], []) --> [].
tails([H|Hs], [T|Tails]) --> [[H|T]], tails(Hs, Tails).

【讨论】:

    【解决方案3】:

    我们将 maplist/[3-4] 与以下辅助谓词之一一起使用:

    list_tail([_|Xs],Xs).
    
    list_head_tail([X|Xs],X,Xs).
    

    让我们运行一些查询!

    ?- maplist(list_head_tail,[[x,x],[b,c],[d,e,f]],Heads,Tails).
    Heads = [x,b,d],
    Tails = [[x],[c],[e,f]].
    

    如果您对尾巴感兴趣,请使用maplist/4list_head_tail/3 ...

    ?- maplist(list_head_tail,[[x,x],[b,c],[d,e,f]],_,Tails).
    Tails = [[x],[c],[e,f]].
    

    ...或者,更简单的是,maplist/3list_tail/2 串联:

    ?- maplist(list_tail,[[x,x],[b,c],[d,e,f]],Tails).
    Tails = [[x],[c],[e,f]].
    

    【讨论】:

    • OP 已经在他们的问题中定义的chop/2 有什么问题?
    • @Boris。 chop/2 是一个错误的名称。
    • @Boris。你是对的。在 Prolog 过去 40 年的历史中,出现并留下了很多名字。尽管如此,以身作则总是正确的时机!
    • slurpspit?
    • @coredump 或library(filesex)?
    【解决方案4】:

    您还可以使用带有findall/3 的有点难看的单线:

    ?- L = [[x,x],[b,c],[d,e,f]],
       findall(T, ( member(M, L), append([_], T, M) ), R).
    R = [[x], [c], [e, f]].
    

    (好吧,从技术上讲,这是一个两行代码。无论哪种方式,您甚至都不需要定义辅助谓词。)

    但绝对更喜欢使用chopmaplist 解决方案,如above 所示。

    如果您手动进行地图列表扩展,并将您的 chop/2 命名好一点,您会得到:

    lists_tails([], []).
    lists_tails([X|Xs], [T|Ts]) :-
        list_tail(X, T),
        lists_tails(Xs, Ts).
    

    并且由于您可以在谓词的头部进行统一,您可以将其转换为:

    lists_tails([], []).
    lists_tails([[_|T]|Xs], [T|Ts]) :-
        lists_tails(Xs, Ts).
    

    但这与您在其他答案中的相同。

    练习:为什么我们不能说:

    ?- maplist(append([_]), R, [[x,x],[b,c],[d,e,f]]).
    

    【讨论】:

    • 基于findall/3 的代码在与非基本术语一起使用时会发生故障。查询?- L = [[A,B],[C,D,E]], findall(T, ( member(M, L), append([_], T, M) ), R). 给出答案L = [[A, B], [C, D, E]], R = [[_G220], [_G211, _G214]].
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-28
    • 1970-01-01
    • 1970-01-01
    • 2011-01-16
    相关资源
    最近更新 更多