5

我有一个创建如下的列表:

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

我希望创建一个作为选项卡的全局变量 AllPosition。所以我做了以下事情:

tab(AllPos).

这是正确的吗?

然后我必须关注问题:我有一个函数可以接收选项卡中的一对。我想删除。所以我这样做了:

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)).

whereerase(List, Element, NewList)从 List 中删除元素 Element 并创建一个新列表 NewList 等于 List 但没有 Element。两个功能membererase在工作。

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

4

3 回答 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 意味着在逻辑中编程。

于 2012-12-19T16:06:24.493 回答
2

添加到伊恩的答案:

通常使用 assert/retract 很慢。许多 prolog 实现对可变全局变量有更有效的方法(例如检查 swi-prolog's lib

现在,如果您想要一个几乎可以像您一样编码的不可变全局变量;您将“声明”它为,myvar(42).但要使用它,您必须这样做:

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

再一次,使用可变全局变量并不是真正的建议,并且由于回溯可能导致非常非常糟糕且难以检测到的错误。

于 2012-05-18T16:37:54.620 回答
1

简而言之:不,您的逻辑不正确。您的代码存在各种小问题和错误,但更大的问题是基本前提。听起来好像您以错误的方式思考问题。一般来说,如果您尝试在 Prolog 程序中更新全局状态,您需要重新考虑您的设计。状态通常由谓词的参数携带,因此我希望将当前集合作为参数传入,而不是统一AllTabs在 的主体中。如果您真的想更新程序的全局状态,那么您需要查看and谓词。place/4Tabsassertretract

一些具体点:

tab(AllPos).

这在头部声明了一个带有未绑定变量的谓词。它或多或少是没有意义的(你可以读到“它是tab真实的,但我们没有关于它真实的信息”)。

AllPos \== [_,_]

的这种用法与AllPos的作用域不同tab/1,所以除了在变量名中共享相同的字符序列外,这两种用法AllPos完全没有关系。

于 2012-05-18T15:16:13.510 回答