【问题标题】:Recursion on a list involving arithmetic operations and counting elements?在涉及算术运算和计数元素的列表上递归?
【发布时间】:2020-11-17 14:14:21
【问题描述】:

我很难真正掌握对 Prolog 列表和递归调用的理解。我一直在开发一个程序来跟踪有多少项目大于列表的头部,然后递归调用这个关系来检查大于下一个元素等等。我已经让我的程序工作到可以计算大于头部的元素数量但是一旦它到达末尾并尝试递归调用下一个元素上的关系就会失败。根据我所做的研究,这就是我所拥有的以及我认为它应该如何工作:

Input - List = [7,2,4,3,6,9,8,10,12,5].

testHead(List).

testHead([H|T]) :-
    greaterThan(H,T,0),
    teastHead(T).

^我的理解是这种关系从列表中获取头部元素并使用头部和列表的其余部分调用大于。在greaterThan完成后,它应该递归调用testHead(T)来测试下一个元素等等。

greaterThan(H,[X|T],C) :-
    H > X ->
    C2 is C+1,
    greaterThan(H,T,C2);
    greaterThan(H,T,C).

^我这里的理解是在头元素、列表的其余部分和一个用于计数的变量中读取的大于。如果 head 大于下一个元素,则增加计数并使用 Tail 和新计数递归调用 greaterThan; else 在不增加计数的情况下递归调用greaterThan。

我的预期输出将是C2 = 12。 (7大于5个元素,2大于0元素,4大于1元素,以此类推)

当前的实际输出是5; 然后是false
我的程序似乎正确地评估和增加了 head 元素,但是当它完成大于该元素时,程序返回 false。我已经尝试在 prolog 中研究和理解列表和递归调用,但我一直在碰壁。我不确定它是否会失败,因为您不能递归地运行增量关系,或者我的列表关系是否存在其他问题。任何有关如何解决此问题以及此处的 prolog 功能如何的说明都会有所帮助。

【问题讨论】:

    标签: list recursion prolog counting


    【解决方案1】:

    让我们从你的第一个代码 sn-p 开始:

    testHead(List).  
    testHead([H|T]) :-
        greaterThan(H,T,0),
        teastHead(T).
    

    你有递归的想法,但我看到了四个问题。

    第一testHead 只有一个属性,这意味着(除了truefalse)你什么也得不到。所以它应该看起来更像这样:testHead([H|T], L) ...

    第二:您需要知道何时停止。这通常是谓词的第一行。你的状态:任何匹配。但它应该这样说:如果没有剩余元素,我可以“返回”一个空列表。 testHead([],[]).

    第三:你用固定值0调用greaterThan(H,T,0),这意味着你想测试“输出”值是否为零。事实并非如此,你想计算东西。所以在这里放一个变量:N

    第四:如果你计算了一个值N,你必须将它转发到输出列表。由于您将从递归调用中获得列表 Nlist,因此您可以创建一个新列表,其中 N 作为头部元素,Nlist 作为尾部元素,然后“返回”这个新列表。

    结论:

    testHead([],[]).
    testHead([H|T],[N|Nlist]) :-
        greaterThan(H,T,N),
        testHead(T,Nlist).
    

    遗憾的是我们还不能测试它,我们必须看看greaterThan/3。 您的 sn-p 如下:

    greaterThan(H,[X|T],C) :-
        H > X ->
        C2 is C+1,
        greaterThan(H,T,C2);
        greaterThan(H,T,C).
    

    还有一些奇怪的地方。

    首先:您需要知道何时停止。通常你会在空列表[] 或者列表只剩下一个元素[A] 时停止。如果您对A 的内容不感兴趣,请使用以下划线_ 开头的“丢弃变量”。这导致:greaterThan(_,[],0)。这意味着:如果我的列表是空的,那么无论引用值是什么,我的列表中都会有 0 个数字。此外,由于规则的顺序很重要,因此您将其置于递归规则之上。

    第二:你的情况是正确的,所以如果H 大于列表的头部X,则执行某事,否则“忽略”@987654344 @ 只需调用没有X 的相同谓词。问题出现在 something 部分:由于C2 的值在C 之前是统一的,因此您需要根据C2 计算C,反之亦然。 C is C2+1 的意思是:我从递归调用中知道 C2 的值,因为 H>X 我想在它的值上加一并“返回”它。

    第三:问greaterThan(H,T,C2)就知道C2的值,所以把C is C2+1放在后面。

    好的,现在我们得到了:

    greaterThan(_,[],0).
    greaterThan(H,[X|T],C) :-
        H > X ->
        greaterThan(H,T,C2),
        C is C2+1;
        greaterThan(H,T,C).
    
    testHead([],[]).
    testHead([H|T],[N|Nlist]) :-
        greaterThan(H,T,N),
        testHead(T,Nlist).
    

    让我们测试一下!

    ?- testHead( [7,2,4,3,6,9,8,10,12,5],L).
    L = [5, 0, 1, 0, 1, 2, 1, 1, 1, 0] ;
    false.
    

    看起来不错,除了您不需要列表而是总数。好的,给你:

    testHead([],0).
    testHead([H|T],New) :-
        greaterThan(H,T,N),
        testHead(T,NN),
        New is NN+N.
    
    ?- testHead( [7,2,4,3,6,9,8,10,12,5],N).
    N = 12 ;
    false.
    

    说明:如果你的输入列表为空,则什么都不做,“返回”中性元素进行添加:0.
    如果您的输入列表有一个头元素H,则通过greaterThan(H,T,N) 计算“大于N 剩余元素”。假设您的代码有效,因此您可以调用 testHead(T,NN) 获取您的尾部列表 T 并获得总和值 NN。如果 NNN 两个值都已知,则添加它们并将其声明为“返回”。

    【讨论】:

    • 这很好地回答了我的问题,谢谢!你很好地解释了一切,仅此一点我就开始更好地理解 Prolog。
    • 安装一个灯泡需要多少 Prolog 程序员?是的。
    猜你喜欢
    • 1970-01-01
    • 2020-07-16
    • 1970-01-01
    • 1970-01-01
    • 2017-09-22
    • 1970-01-01
    • 2012-02-26
    • 2018-04-02
    • 2019-03-04
    相关资源
    最近更新 更多