gpt4 book ai didi

prolog - 如何避免在Prolog中使用assert和retractall来实现全局(或状态)变量

转载 作者:行者123 更新时间:2023-12-04 14:01:38 25 4
gpt4 key购买 nike

我经常在 Prolog 中编写代码,其中涉及一些算术计算(或整个程序中重要的状态信息),首先获取存储在谓词中的值,然后重新计算该值,最后使用 retractall 存储该值。和 assert因为在 Prolog 中我们不能使用 is 为变量赋值两次(从而使几乎所有需要修改的变量都成为全局变量)。我开始知道这在 Prolog 中不是一个好的做法。对此,我想问:

  • 为什么在 Prolog 中这是一个不好的做法(尽管我自己不喜欢通过上述步骤只是为了拥有一种灵活的(可修改的)变量)?
  • 避免这种做法的一般方法有哪些?小例子将不胜感激。

  • 附言我刚开始学习 Prolog。我确实有像 C 这样的语言的编程经验。

    编辑以进一步澄清

    下面给出了我想说的一个不好的例子(在 win-prolog 中):
    :- dynamic(value/1).
    :- assert(value(0)).

    adds :-
    value(X),
    NewX is X + 4,
    retractall(value(_)),
    assert(value(NewX)).

    mults :-
    value(Y),
    NewY is Y * 2,
    retractall(value(_)),
    assert(value(NewY)).

    start :-
    retractall(value(_)),
    assert(value(3)),
    adds,
    mults,
    value(Q),
    write(Q).

    然后我们可以这样查询:
    ?- start.

    在这里,很琐碎,但是在实际程序和应用中,上面展示的全局变量的方法就不可避免了。有时上面给出的列表如 assert(value(0)) ...随着用于定义更多变量的更多断言谓词变得很长。这样做是为了使不同函数之间的值通信成为可能,并在程序运行时存储变量的状态。

    最后,我还想知道一件事:
    尽管您提出了各种解决方案来避免上述做法,但何时无法避免?

    最佳答案

    避免这种情况的一般方法是考虑计算状态之间的关系:您使用一个参数来保存计算前与程序相关的状态,第二个参数描述一些计算后的状态。例如,要描述对值 V0 的一系列算术运算, 您可以使用:

    state0_state(V0, V) :-
    operation1_result(V0, V1),
    operation2_result(V1, V2),
    operation3_result(V2, V).

    请注意状态(在您的情况下:算术值)如何通过谓词进行线程化。命名约定 V0 -> V1 -> ... -> V可轻松扩展到任意数量的操作,并有助于牢记 V0是初始值, V是应用各种操作后的值。每个需要访问或修改状态的谓词都有一个参数,允许您将状态传递给它。

    像这样线程化状态的一个巨大优势是,您可以轻松地独立推理每个操作:您可以对其进行测试、调试、使用其他工具进行分析等,而无需设置任何隐式全局状态。另一个巨大的好处是,您可以在更多方向上使用您的程序,前提是您使用了足够通用的谓词。例如,您可以问:哪些初始值会导致给定的结果?
    ?- state0_state(V0, given_outcome).

    当使用命令式风格时,这当然是不可能的。因此,您应该使用约束而不是 is/2 , 因为 is/2只在一个方向上起作用。约束更容易使用,并且是低级算术的更通用的现代替代方案。

    动态数据库也比线程状态通过变量慢,因为它在每个 assertz/1 上执行索引等。 .

    关于prolog - 如何避免在Prolog中使用assert和retractall来实现全局(或状态)变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19005042/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com