How to create global variable in prolog

16,568

Solution 1

In SWI-Prolog you can use: b_setval(name, value) and b_getval(name, value). And in case you don't want the values change back in case of backtracking, you can make them actual global by using: nb_setval(name, value) and nb_getval(name, value).

Thus for example if you have a program and you want to check how often it went through a certain path, you can use:

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

This is good for some experimental cases, but in general you will want to avoid global variables in Prolog because Prolog means programming in logic.

Solution 2

adding to Ian's answer:

generally using assert/retract is slow. many prolog implementations have more efficient ways for mutable global variables (for example check swi-prolog's lib )

now, if you want an immutable global variable that can be encoded almost like you did; you will "declare" it as myvar(42). but to use it you will have to do this:

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

again, using mutable global variables is not really suggested and can lead to very, very bad and hard to detect bugs due to backtracking.

Solution 3

In brief: no, your logic is not correct. There are various minor issues and bugs with your code, but the bigger problem is the basic premise. It sounds as though you're thinking of the problem the wrong way. In general, if you're trying to update global state in a Prolog program you need to rethink your design. State is more usually carried by the arguments to predicates, so rather than unifying AllTabs in the body of place/4, I would have expected the set of current Tabs to be passed in as an argument. If you really want to update the global state of your program, then you need to look to the assert and retract predicates.

Some specific points:

tab(AllPos).

this declares a predicate with an unbound variable in the head. It is more-or-less meaningless (you could read is at "it is the case that tab is true of something, but we have no information about what it is true of").

AllPos \== [_,_]

This use of AllPos is in a different scope to tab/1, so apart from sharing the same sequence of characters in the variable name, the two uses of AllPos have no relationship at all.

Share:
16,568
FriedRike
Author by

FriedRike

I'm a computer science student with a lot of questions ;)

Updated on June 04, 2022

Comments

  • FriedRike
    FriedRike almost 2 years

    I have a list that I create as follows:

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

    I wish to create a global variable AllPosition that is a tab. So I did the following:

    tab(AllPos).
    

    Is this right?

    Then I have to follow problem: I have a function that receives one of the pair in tab. That I wish to remove. So I did this:

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

    where erase(List, Element, NewList) erases the element Element from List and creates a new list NewList equal to List but without Element. Both functions member and erase are working.

    The thing is... As you might have noticed I use AllPoseverywhere. That's because I want to, I want to modify it so I can use it later (after having removed some elements from it), in another function. Is my logic right? Will I be able to use modified AllPos in another function? Thanks