How to create global variable in prolog
Asked Answered
S

3

5

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

Sarabia answered 18/5, 2012 at 15:0 Comment(1)
Please also see the question and answers on how to avoid global variables in Prolog.Heng
S
5

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.

Slotter answered 19/12, 2012 at 16:6 Comment(0)
H
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.

Healthy answered 18/5, 2012 at 16:37 Comment(1)
The link in this answer appears to be broken.Burnell
I
1

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.

Iphagenia answered 18/5, 2012 at 15:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.