如何在Prolog中创建全局变量

5

我有一个列表,创建方式如下:

tab([(top,left),(top,middle),(top,right),(center,left),(center,middle),
     (center,right),(bottom,left),(bottom,middle),(bottom,right)]).

我希望创建一个名为AllPosition的全局变量,它是一个表格。因此我执行了以下操作:

tab(AllPos).

这样对吗?

然后我面临一个问题: 我有一个函数,它接收tab中的一对元素。我希望删除其中一个元素,所以我做了这个操作:

place(Line, Column, Tab) :-
AllPos \== [_,_] /*while AllPos isn't empty - not sur if this is done this way*/ -> (member((Line,Column), AllPos) -> (erase(AllPos, (Line,Column), AllPos)).

其中erase(List, Element, NewList)是从列表List中删除元素Element并创建一个新的列表NewList,它与不包含Element的List相同。这两个函数membererase都可以使用。

问题是...你可能已经注意到我到处使用AllPos。那是因为我想要这样做,我想修改它以便稍后在另一个函数中使用(在从中删除一些元素后)。我的逻辑正确吗?我能在另一个函数中使用修改后的AllPos吗? 谢谢


请参阅有关如何在Prolog中避免全局变量的问题和答案。 - mat
3个回答

5
在SWI-Prolog中,您可以使用b_setval(name, value)b_getval(name, value)。如果您不希望在回溯时更改值,则可以通过使用nb_setval(name, value)nb_getval(name, value)使它们成为实际的全局变量。

例如,如果您有一个程序,并且想要检查它经过某个特定路径的次数,可以使用:

recursive(100).
recursive(X) :- add, Y is X + 1, recursive(Y).

add :- nb_getval(counter, C), CNew is C + 1, nb_setval(counter, CNew).

testRecursion
:-
    % Set counter to zero
    nb_setval(counter, 0),

    % Run some code with 'add'
    recursive(0), !,

    % Print the results
    nb_getval(counter, CounterValue),
    write('Steps: '), writeln(CounterValue).

虽然某些试验性的情况下使用全局变量还是可以的,但总体上来说,在Prolog中应该避免使用全局变量,因为Prolog意味着逻辑编程。


2

对Ian的回答进行补充:

通常使用assert/retract很慢。许多Prolog实现都有更高效的方法来处理可变全局变量(例如检查swi-prolog的 lib

如果你想要一个不可变的全局变量,可以几乎按照你所做的方式进行编码。你会将其“声明”为myvar(42),但要使用它,你必须这样做:

foo:-
   myvar(Var),
   do_something(Var).

再次强调,不建议使用可变全局变量,因为这可能会导致非常恶劣且难以检测的错误,因为会回溯。


这个答案中的链接(http://www.swi-prolog.org/pldoc/doc_for?object=section%282,%276.3%27,swi%28%27/doc/Manual/gvar.html%27%29%29)似乎已经失效了。 - Anderson Green

1
简而言之:不,你的逻辑是错误的。你的代码存在各种小问题和错误,但更大的问题是基本前提。听起来你对问题的思考方式是错误的。一般来说,如果你想在Prolog程序中更新全局状态,你需要重新考虑你的设计。状态通常由谓词的参数传递,所以我希望当前的标签集合作为参数传入,而不是在place/4的主体中统一AllTabs
如果你真的想要更新程序的全局状态,那么你需要使用assertretract谓词。
一些具体的要点:
tab(AllPos).

这声明了一个带有未绑定变量的谓词。它几乎没有意义(你可以将其理解为“tab 对某些东西为真,但我们没有关于它为真的信息”)。

AllPos \== [_,_]

这里使用的AllPostab/1处于不同的作用域,因此除了在变量名中共享相同的字符序列外,这两个AllPos的使用完全没有关系。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接