2013-10-17 5 views
6

ich über einen Prolog fragen, die einen eingebauten in Aufruf wie folgt umfassen könnte:Unterstützt eine Version von Prolog eine Abstraktion höherer Ordnung von Akkumulatoren?

accum(generator, filter, accumulator) 
Calculates all solutions to generator. 
For each one, if filter can be proved, accumulator is proved. 
Backtracks to find all solutions to filter and generator. 
Accumulator may backtrack internally, but multiple proofs of accumulator are 
    conjoined, not backtracked. 

So zum Beispiel eine Liste zusammenzufassen, ohne Rekursion Sie schreiben konnte:

X is 0, accum(member(Val,List), True, X is X + Val). 

Ist Gibt es einen Prolog mit diesem Konstrukt oder ein Äquivalent? Bedenken Sie, dass ich bei Prolog ein bisschen Neuling bin und vielleicht etwas Offensichtliches vermisse.

+0

In Merkur würde man einfach ein Prädikat namens accum schreiben, das dies tut.Da Sie jedoch keine Ziele als Parameter verwenden können (wie Sie es in der Frage getan haben), müssen Sie stattdessen lambdas verwenden. –

+0

@PaulBone Das Ergebnis hängt von der Berechnung aller Lösungen für den Generator ab. Letztendlich wird es also immer noch erforderlich sein, etwas aus Mercurys "solutions" -Modul aufzurufen, es sei denn, Sie möchten nicht-logische Funktionen verwenden (in diesem Fall gilt das Adverb "einfach" nicht;)). –

Antwort

3

Ich nehme an, du meinst ohne explizite Rekursion? Wenn dies der Fall ist, können Sie eine Implementierung der Prädikatliste höherer Ordnung links zusammen mit einem Lambda-Ausdruck verwenden, um die Notwendigkeit eines Hilfsprädikats zu vermeiden. Mit Logtalk als Beispiel können Sie schreiben:

?- Sum0 is 0, meta::fold_left([X,Y,Z]>>(Z is Y+X), Sum0, [1,2,3], Sum). 
Sum0 = 0, 
Sum = 6. 

Logtalk als Backend-Compiler verwenden, können die meisten Implementierungen Prolog (http://logtalk.org/). Sie können auch die lambda-Bibliothek von Ulrich verwenden (http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/ISO-Hiord.html) mit einem unterstützten Prolog-Compiler zusammen mit einer Prolog-Bibliothek, die das Prädikat falte links für das gleiche Ergebnis liefert. Jetzt mit YAP als Beispiel:

$ yap 
... 
?- use_module(library(lambda)). 
... 
?- use_module(library(maplist)). 
... 
?- Sum0 is 0, foldl(\X^Y^Z^(Z is Y+X), [1,2,3], Sum0, Sum). 
Sum = 6, 
Sum0 = 0. 

Kurz gesagt, die Falten links Prädikats iteriert über eine Liste, rekursiv ist, den Verschluss in seiner ersten Argument einer Listenelement und dem Speicher der Anwendung der endgültigen Akkumulatorwert zurückkehrt.

+0

Die Frage war, dass die Lösungen durch Backtracking generiert werden sollten. Ihre Antwort beginnt mit der bereits generierten Lösung "[1,2,3]" und beantwortet die Frage nicht. –

+0

'[1,2,3]' ist ** nicht ** die Liste der Lösungen, es ist die ** Eingabe ** Liste, das gleiche, das Sie im 'member (Val, List)' Bit in der übergeben würden Frage Beispiel. –

+0

Sie haben nur das Beispiel gelöst, nicht den allgemeinen Fall. Die Frage war eindeutig, wiederhole ich, dass die Lösungen durch Backtracking generiert werden. –

5

SWI-Prolog library(aggregate) verfügt über eine leistungsfähige Schnittstelle, zum Beispiel

aggregate_all(sum(Val), member(Val,List), Sum) 

die (scheinbar simple) Aufteilung der Variablen unter Aggregation und Generation ist mit einem Prädikat erhalten, foreach/2, das könnten Sie interessieren.

In SWI-Prolog Sie ?- edit(library(aggregate)). tun können, die Interna zu studieren ...

Bibliothek (Aggregat) relativ ineffizient ist, aber mit SWI-Prolog nb_ (nicht backtrackable) Datenstrukturen gekoppelt ist sehr gut, seine Arbeit tun ...

Über nicht rückverfolgbare Datenstrukturen: here ist ein Beispiel für meinen "selbstgebauten" Akku, implementiert mit nb_setarg/3.

2

In der Standardbibliothek von Mercury bietet das Modul "solutions" Funktionen wie diese.

Beachten Sie, dass X is X + Val X keinen neuen Wert zuweist. Es ist eine Aussage, die wahr ist, wenn Val Null ist, und falsch, wenn es eine andere Zahl ist, was wahrscheinlich nicht das ist, was Sie meinen. Akkumulatoren wie diese werden typischerweise als eine Beziehung zwischen dem Anfangswert und dem Endwert ausgedrückt.

:- import_module solutions. 
... 
sumlist(List, Sum) :- 
    Generator = (pred(Val::out) is nondet :- member(Val, List), true), 
    Accumulator = (pred(X::in, Y::in, Z::out) is det :- Z = X + Y), 
    aggregate(Generator, Accumulator, 0, Sum). 

keine Notwendigkeit für einen separaten Filter Argument Dort, wie es als Teil des Generators enthalten sein können:

In Mercury, könnte Ihr Beispiel geschrieben werden.

Verwandte Themen