2012-05-18 25 views
5

ich eine Liste, die ich wie folgt erstellen:So erstellen Sie globale Variable in Prolog

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

Ich möchte eine globale Variable AllPosition schaffen, die ein Register ist. Also habe ich folgendes gemacht:

tab(AllPos). 

Ist das richtig?

Dann muss ich Problem verfolgen: Ich habe eine Funktion, die eine der beiden in Registerkarte erhält. Das möchte ich entfernen. Also tat ich dies:

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

wo erase(List, Element, NewList) löscht das Element Element aus Liste und erstellt eine neue Liste NewList gleich Liste aber ohne Element. Beide Funktionen member und erase funktionieren. Die Sache ist ... Wie Sie vielleicht bemerkt haben, verwende ich AllPos überall. Das ist, weil ich möchte, ich möchte es ändern, damit ich es später (nachdem ich einige Elemente daraus entfernt habe), in einer anderen Funktion verwenden kann. Ist meine Logik richtig? Kann ich modifizierte AllPos in einer anderen Funktion verwenden? Danke

+0

Bitte beachten Sie auch die Frage und Antworten zur Vorgehensweise [** globale Variablen vermeiden **] (http://stackoverflow.com/questions/19005042/how-to-avoiding-using-assert-and-retractall-in) -prolog-zu-implementieren-global-oder-state) in Prolog. – mat

Antwort

0

Kurz gesagt: Nein, Ihre Logik ist nicht korrekt. Es gibt verschiedene kleinere Probleme und Bugs mit Ihrem Code, aber das größere Problem ist die Grundvoraussetzung. Es klingt, als ob Sie das Problem auf die falsche Art und Weise denken. Wenn Sie versuchen, den globalen Status in einem Prolog-Programm zu aktualisieren, müssen Sie im Allgemeinen Ihr Design überdenken. Der Zustand wird häufiger von den Argumenten für Prädikate übernommen, also würde ich anstelle der Vereinigung AllTabs im Körper von place/4 erwartet haben, dass der Satz der aktuellen Tabs als Argument übergeben wird. Wenn Sie wirklich möchten den globalen Status Ihres Programms zu aktualisieren, dann müssen Sie auf die assert und retract Prädikaten schauen.

Einige spezifischen Punkte:

tab(AllPos). 

dies im Kopf ein Prädikat mit einer ungebundenen Variable deklariert. Es ist mehr oder weniger bedeutungslos (Sie könnten lesen bei "es ist der Fall, dass tab für etwas wahr ist, aber wir haben keine Informationen darüber, was es wahr ist").

AllPos \== [_,_] 

Diese Verwendung von AllPos ist in einem anderen Bereich zu tab/1, so abgesehen von der gleichen Folge von Zeichen in den Variablennamen teilen, die beiden Verwendungen von AllPos überhaupt keine Beziehung haben.

1

Hinzufügen zu Ians Antwort:

allgemein mit assert/Rückzug langsam ist.viele Prolog-Implementierungen haben effizientere Möglichkeiten für wandelbar globale Variablen (zB Scheck swi-prolog der lib)

jetzt, wenn Sie eine unveränderliche globale Variable wollen, die fast kodiert werden kann, wie Sie haben; Sie „erklären“ als myvar(42). aber, es zu benutzen Sie, dies zu tun haben:

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

wieder wandelbar globale Variablen verwendet, ist nicht wirklich vorgeschlagen und zu sehr führen kann, sehr schlecht und schwer Fehler zu erkennen wegen Backtracking.

+0

[Der Link in dieser Antwort] (http://www.swi-prolog.org/pldoc/doc_for?object=section%282,%276.3%27,swi%28%27/doc/Manual/gvar.html% 27% 29% 29) scheint gebrochen zu sein. –

+0

@AndersonGreen Prost, repariert! –

4

In SWI-Prolog können Sie verwenden: b_setval(name, value) und b_getval(name, value). Und falls Sie nicht möchten, dass sich die Werte im Falle eines Backtrackings ändern, können Sie sie mit den folgenden Werten global machen: nb_setval(name, value) und nb_getval(name, value).

So zum Beispiel, wenn Sie ein Programm haben, und Sie wollen, um zu überprüfen, wie oft es durch einen bestimmten Weg ging, können Sie verwenden:

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

Das ist gut für einige experimentelle Fälle, aber in der Regel werden Sie möchte in Prolog globale Variablen vermeiden, weil Prolog Programmieren in der Logik bedeutet.