【问题标题】:Building lists recursively with values returned from other predicates in Prolog使用从 Prolog 中的其他谓词返回的值递归构建列表
【发布时间】:2014-02-15 16:58:20
【问题描述】:

免责声明:这是一项学校作业。

Prolog 的新手,对基础知识有相当的了解。赋值是对多项式进行微分。这部分不是问题。我设计了一种算法,它可以在 Prolog 中工作并实现,令我满意。此时,调用我的 diff_term 谓词每次都会产生一个适当微分的多项式项。

但是,当我将一个完整的多项式传递给我的 diff_poly 谓词时,它的工作是解析术语,将它们传递给微分,并将它们重新收集到一个列表中以返回给用户,事情就崩溃了。我的问题是将返回的多项式项(列表)递归地添加到完全微分多项式(另一个列表)中。我咨询了许多相关的 Stackoverflow 问题,发现这个问题特别有用:

Prolog - recursive list building

为了理解它,我彻底阅读并重新创建了相同的程序。然而,主要区别在于,在我的情况下,我添加到列表中的值是由其他谓词返回的,而不是在内置列表的同一谓词中创建的。

以下代码包含我的diff_poly 谓词,然后调用diff_termdiff_term 然后调用许多其他自制谓词来执行算法;但是,这些都不是问题,如上所述,差异化效果很好。您可能仅通过谓词名称就可以理解我的算法方法。

diff_poly 谓词是唯一存在的diff_poly;没有基本案例或其他变体,因为我可以假设(根据分配规范)所有输入都将是一致且有效的格式。然而,还有一些其他的diff_term 谓词用于处理术语内容的变化,所有这些都返回适当的术语导数。

如果我按原样调用diff_poly,我会得到“假”作为我的回报。如果我注释掉该谓词的最后一行并取消注释它前面的那个,我会得到一个返回给我的有区别的术语,这是预期的,因为它们不是递归调用,并证明从diff_term 调用/返回有效。

基本上我只需要一些关于如何构建要返回的列表的指导。我尝试过追加、插入等,但我认为头部匹配策略(在上面的问题中概述)是可行的方法,但我执行不正确。任何见解都值得赞赏。

% differentiates a polynomial with respect to given variable
% polynomials are parsed into terms, and terms are passed to diff_term
diff_poly([Term | Rest], DiffVar, DiffedPoly) :-
    diff_term(Term, DiffVar, DiffedTerm),
%    DiffedPoly = DiffedTerm.
    diff_poly(Rest, DiffVar, [DiffedTerm | DiffedPoly]).


% term is a coefficient and at least one var/exp pair in its member variable list
% term includes occurrence of variable to differentiate with respect to
diff_term([Coef | Rest], DiffVar, Return) :-
    flatten(Rest, FlatList),
    member(DiffVar, FlatList),
    index_of(FlatList, DiffVar, Index),
    nth1(Index, FlatList, Exp),
    Exp > 1, NewCoef is Coef * Exp, NewExp is Exp - 1,
    remove_at(FlatList, Index, RemoveList),
    insert_at(NewExp, RemoveList, Index, InsertList),
    split_varlist(InsertList, DoneList),
    Return = [NewCoef | DoneList], !.

【问题讨论】:

    标签: recursion prolog


    【解决方案1】:

    假设您的 diff_term 很好(您可以在 Prolog 提示符下进行模块化测试),让我们看看 diff_poly

    diff_poly([Term | Rest], DiffVar, DiffedPoly) :-
        diff_term(Term, DiffVar, DiffedTerm),
    %    DiffedPoly = DiffedTerm.
        diff_poly(Rest, DiffVar, [DiffedTerm | DiffedPoly]).
    

    这个子句说DiffedPoly是多项式[Term|Rest]相对于DiffVar微分。到目前为止听起来不错。

    您在子句中的第一个表达式是,*DiffedTermTermDiffVar 的微分。听起来也不错。

    下一个注释行说将DiffedPolyDiffedTerm 统一起来。这将不再有意义,因为完全微分多项式通常不仅仅是微分项(当然,除非多项式只有一项)。让我们把它注释掉。

    最后,我们有:

    diff_poly(Rest, DiffVar, [DiffedTerm | DiffedPoly])
    

    这就是说,多项式的其余部分(没有第一项)对DiffVar 微分的结果是第一项对DiffVar 微分(即DiffTerm),然后是完全微分多项式 (DiffedPoly)。如果你这么想,那是没有意义的。写得好像你改变了DiffedPoly 的真正含义。该查询应该表示,完全微分多项式 (DiffedPoly) 是初始项 (DiffedTerm) 的微分,然后是多项式其余部分的微分(Rest 相对于 @ 的微分987654341@)。将最后的描述翻译成 Prolog,然后你就差不多了。

    几乎...这是因为递归需要一个基本情况。空多项式会发生什么?您还需要为这种情况添加diff_poly([], <something>, <something>)

    【讨论】:

    • 好了。这对我来说完美解决了。谢谢你把它说出来,让我的思绪正确地围绕着它。干杯!
    • @carofthecdr 很高兴你知道了。 :)
    【解决方案2】:

    我认为您应该改变信息流的“方向”,并添加一个基本案例。 像这样简单的东西应该可以工作

    % we need this one, to match when Rest become an empty list
    diff_poly([], _DiffVar, []).
    
    diff_poly([Term | Rest], DiffVar, [DiffedTerm | DiffedPoly]) :-
        diff_term(Term, DiffVar, DiffedTerm),
        diff_poly(Rest, DiffVar, DiffedPoly).
    

    这个列表处理模式可以通过maplist/3的介绍来简化

    diff_poly(TermList, DiffVar, DiffedList) :-
        maplist(diff_poly_(DiffVar), TermList, DiffedList).
    
    % since maplist appends lists'elements to argument list, we need a service predicate
    % otherwise, and better, a swap of diff_term arguments could do
    diff_poly_(DiffVar, Term, Diffed) :-
        diff_term(Term, DiffVar, Diffed).
    

    【讨论】:

    • 感谢您的回答。实际上,一旦第一个答案出现,我就已经开始接受第一个答案的建议。我的结果看起来与您的结果惊人地相似(没有地图列表的 on)。干杯!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多