Compare commits
5 commits
5726f33d34
...
e5c61c89da
Author | SHA1 | Date | |
---|---|---|---|
e5c61c89da | |||
28168cb0f1 | |||
2c6dfb77a0 | |||
f4d96d4143 | |||
6f1b252f52 |
12 changed files with 236 additions and 98 deletions
BIN
build/gpl.jar
Normal file
BIN
build/gpl.jar
Normal file
Binary file not shown.
|
@ -7,6 +7,16 @@
|
||||||
url = {https://doi.org/10.1515/9781400863440},
|
url = {https://doi.org/10.1515/9781400863440},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@book{toman-2008,
|
||||||
|
author = {Toman, David},
|
||||||
|
booktitle = {{Computational Logic}},
|
||||||
|
title = {Chapter 9. SLD-Resolution And Logic Programming (PROLOG)},
|
||||||
|
pages = {410--475},
|
||||||
|
publisher = {University of Waterloo},
|
||||||
|
year = {2008},
|
||||||
|
url = {https://cs.uwaterloo.ca/~david/cl/}
|
||||||
|
}
|
||||||
|
|
||||||
@book{deransart-1996,
|
@book{deransart-1996,
|
||||||
author = {given-i=P, given=Pierre, family=Deransart and given-i=A, given=AbdelAli, family=Ed-Dbali and given-i=L, given=Laurent, family=Cervoni},
|
author = {given-i=P, given=Pierre, family=Deransart and given-i=A, given=AbdelAli, family=Ed-Dbali and given-i=L, given=Laurent, family=Cervoni},
|
||||||
date = {1996-01-01},
|
date = {1996-01-01},
|
||||||
|
@ -23,6 +33,14 @@
|
||||||
note = "[Online; accessed 12-May-2025]"
|
note = "[Online; accessed 12-May-2025]"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@article{iso1995iec,
|
||||||
|
title={IEC 13211-1: 1995: Information Technology—Programming Languages—Prolog—Part 1: General Core},
|
||||||
|
author={ISO, ISO and ISO, IEC},
|
||||||
|
journal={ISO: Geneva, Switzerland},
|
||||||
|
pages={1--199},
|
||||||
|
year={1995}
|
||||||
|
}
|
||||||
|
|
||||||
@book{russell2016,
|
@book{russell2016,
|
||||||
author = {Russell, Stuart and Norvig, Peter},
|
author = {Russell, Stuart and Norvig, Peter},
|
||||||
booktitle = {{Artificial Intelligence A Modern Approach, Global Edition}},
|
booktitle = {{Artificial Intelligence A Modern Approach, Global Edition}},
|
||||||
|
@ -37,3 +55,11 @@ The long-anticipated revision of this best-selling text offers the most comprehe
|
||||||
doi = {},
|
doi = {},
|
||||||
url = {https://elibrary.pearson.de/book/99.150005/9781292153971}
|
url = {https://elibrary.pearson.de/book/99.150005/9781292153971}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@software{unknown-author-2025,
|
||||||
|
date = {2025-04-25},
|
||||||
|
title = {SWI-Prolog},
|
||||||
|
type = {software},
|
||||||
|
url = {https://www.swi-prolog.org/},
|
||||||
|
version = {9.3.24},
|
||||||
|
}
|
||||||
|
|
BIN
documentatie/renaming.png
Normal file
BIN
documentatie/renaming.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
Binary file not shown.
|
@ -7,9 +7,11 @@
|
||||||
\usepackage[dutch]{babel} % Nederlands taal
|
\usepackage[dutch]{babel} % Nederlands taal
|
||||||
\usepackage[style=apa]{biblatex} % Bronnen
|
\usepackage[style=apa]{biblatex} % Bronnen
|
||||||
\usepackage{enumitem} % Aanpasbare lijsten
|
\usepackage{enumitem} % Aanpasbare lijsten
|
||||||
\usepackage[margin=1in]{geometry} % Sane marges
|
\usepackage{float} % Figures
|
||||||
|
\usepackage[margin=2cm]{geometry} % Sane marges
|
||||||
|
\usepackage{graphicx} % Figures
|
||||||
\usepackage{hyperref} % Hyperlinks
|
\usepackage{hyperref} % Hyperlinks
|
||||||
\usepackage{minted} % Syntax highlighting
|
\usepackage{minted} % Syntax highlighting
|
||||||
\usepackage{multicol} % Meerdere kolommen
|
\usepackage{multicol} % Meerdere kolommen
|
||||||
\usepackage{url} % Beter geformatteerde URLs
|
\usepackage{url} % Beter geformatteerde URLs
|
||||||
|
|
||||||
|
@ -26,14 +28,18 @@
|
||||||
% KERN: Wat is Ghent Prolog?
|
% KERN: Wat is Ghent Prolog?
|
||||||
Ghent Prolog is een command-line Prolog interpreter geschreven in Kotlin.
|
Ghent Prolog is een command-line Prolog interpreter geschreven in Kotlin.
|
||||||
Het biedt een subset van de functionaliteit van SWI-Prolog, waaronder database operaties en meta abstracties.
|
Het biedt een subset van de functionaliteit van SWI-Prolog, waaronder database operaties en meta abstracties.
|
||||||
|
Hoewel het programma nog niet als equivalent van SWI-Prolog kan worden beschouwd, is Ghent Prolog een nuttig leerproject.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
\section{Overzicht}\label{sec:overzicht}
|
\section{Overzicht}\label{sec:overzicht}
|
||||||
|
|
||||||
|
% KERN: Insteek
|
||||||
|
Ghent Prolog is een proof of concept van een Prolog interpreter, als alternatief voor SWI-Prolog.
|
||||||
|
Het volgt grotendeels ~\cite[de ISO Prolog standaard]{iso1995iec}, maar is niet volledig compatibel.
|
||||||
|
|
||||||
% KERN: Programmeertaal, libraries, etc.
|
% KERN: Programmeertaal, libraries, etc.
|
||||||
Ghent Prolog werd geschreven in Kotlin en maakt gebruik van zowel object-gerichte als functionele concepten.
|
Ghent Prolog werd geschreven in Kotlin en maakt gebruik van zowel object-gerichte als functionele concepten.
|
||||||
|
|
||||||
Er werden twee bibliotheken gebruikt:
|
Er werden twee bibliotheken gebruikt:
|
||||||
\href{https://github.com/h0tk3y/better-parse}{\texttt{better-parse}}, voor het parsen van een gegeven grammatica, en
|
\href{https://github.com/h0tk3y/better-parse}{\texttt{better-parse}}, voor het parsen van een gegeven grammatica, en
|
||||||
\href{https://github.com/xenomachina/kotlin-argparser}{\texttt{kotlin-argparser}}, voor het gebruik van command-line argumenten.
|
\href{https://github.com/xenomachina/kotlin-argparser}{\texttt{kotlin-argparser}}, voor het gebruik van command-line argumenten.
|
||||||
|
@ -42,27 +48,19 @@
|
||||||
De verschillende fases van een interpreter (lexing, parsing, evaluatie, etc.) zijn in Ghent Prolog zo goed mogelijk gescheiden.
|
De verschillende fases van een interpreter (lexing, parsing, evaluatie, etc.) zijn in Ghent Prolog zo goed mogelijk gescheiden.
|
||||||
Op die manier blijft de implementatie modulair en uitbreidbaar.
|
Op die manier blijft de implementatie modulair en uitbreidbaar.
|
||||||
|
|
||||||
|
De volgende secties concentreren zich op de evaluatie-fase van de interpreter.
|
||||||
\section{Lexing, parsing en preprocessing}\label{sec:lexing-parsing-preprocessing}
|
Voor meer informatie over de lexing en parsing, zie sectie~\ref{sec:lexing-parsing-preprocessing}.
|
||||||
|
|
||||||
Traditioneel zijn de lexer en parser aparte componenten.
|
|
||||||
Om tijd te besparen werd echter voor het lexen en parsen van Prolog broncode en REPL-invoer gebruik gemaakt van de \texttt{better-parse} bibliotheek.
|
|
||||||
De parser maakt gebruik van een vereenvoudigde Prolog grammatica, gebaseerd op
|
|
||||||
\href{https://github.com/antlr/grammars-v4/blob/master/prolog/prolog.g4}{de ANTLR Prolog grammatica},
|
|
||||||
\href{https://sicstus.sics.se/sicstus/docs/3.7.1/html/sicstus_45.html#SEC370}{SICStus Prolog Full Prolog Syntax} en
|
|
||||||
\href{https://github.com/simonkrenger/ch.bfh.bti7064.w2013.PrologParser/blob/2c06e5a221c1cc51ba766304250749a7f0caed8c/doc/prolog-bnf-grammar.txt}{simonkrenger/PrologParser's BNF}.
|
|
||||||
|
|
||||||
Omdat de lexer en parser niet op maat gemaakt zijn, worden ze bewust zo eenvoudig mogelijk gehouden.
|
|
||||||
Hun verantwoordelijkheid is het omzetten van inputtekst naar een basis Abstract Syntax Tree (AST), die enkel uit generieke Prolog termen bestaat.
|
|
||||||
Daarna worden de termen in de AST omgezet naar specifieke klassen die de ingebouwde operatoren voorstellen.
|
|
||||||
|
|
||||||
|
|
||||||
\section{Programma en REPL}\label{sec:programma-repl}
|
\section{Programma en REPL}\label{sec:programma-repl}
|
||||||
|
|
||||||
|
% KERN: Methode
|
||||||
|
Ghent Prolog's evaluatiemethode kan gezien worden als een vorm van \textit{backward chaining} (\cite{russell2016}), maar komt niet exact overeen met de definitie.
|
||||||
|
|
||||||
% KERN: Datastructuur
|
% KERN: Datastructuur
|
||||||
Ghent Prolog maakt gebruik van functie-oproepen streams om het backtracking mechanisme te implementeren.
|
Ghent Prolog maakt gebruik van functie-oproepen en streams om een backtracking mechanisme te implementeren.
|
||||||
Bijzondere logica met betrekking tot \textit{choicepoints} en foutenafhandeling maakt gebruik van de Kotlin \texttt{Result} klasse.
|
Bijzondere logica met betrekking tot \textit{choicepoints} en foutenafhandeling maakt gebruik van de Kotlin \mintinline{kotlin}{Result} klasse.
|
||||||
Om de resultaten van unificatie en evaluatie lazy te verwerken, wordt er gebruik gemaakt van Kotlin \texttt{Sequence}s (\textit{lazy streams}).
|
Om de resultaten van unificatie en evaluatie \textit{lazy} te verwerken, wordt er gebruik gemaakt van Kotlin \mintinline{kotlin}{Sequence}'s (\textit{lazy streams}).
|
||||||
|
|
||||||
Meer specifiek wordt er gebruik gemaakt van de volgende types:
|
Meer specifiek wordt er gebruik gemaakt van de volgende types:
|
||||||
|
|
||||||
|
@ -95,22 +93,39 @@
|
||||||
\href{https://www.swi-prolog.org/pldoc/man?section=glossary}{SWI-Prolog's Glossary of Terms},
|
\href{https://www.swi-prolog.org/pldoc/man?section=glossary}{SWI-Prolog's Glossary of Terms},
|
||||||
met bijkomende inspiratie uit~\cite{deransart-1996}.
|
met bijkomende inspiratie uit~\cite{deransart-1996}.
|
||||||
|
|
||||||
\subsection{Evaluatiestrategie}\label{subsec:evaluatiestrategie}
|
|
||||||
|
\section{Evaluatiestrategie}\label{sec:evaluatiestrategie}
|
||||||
|
|
||||||
% KERN: Evaluatiestrategie
|
% KERN: Evaluatiestrategie
|
||||||
Ghent Prolog maakt gebruik van een depth-first zoekstrategie.
|
Ghent Prolog maakt gebruik van een depth-first zoekstrategie.
|
||||||
Op het moment dat de databank een goal gevraagd wordt (\textit{query}), geeft die de goal beurtelings door aan de overeenkomende clauses, aan de hand van \mintinline{kotlin}{solve}.
|
|
||||||
Eerst wordt de goal met de head van de clause geünificeerd, wat nieuwe substituties kan introduceren.
|
Op het moment dat de databank een goal gevraagd wordt (\textit{query}), worden de volgende stappen doorlopen:
|
||||||
Daarna wordt de body van de clause geëvalueerd (\mintinline{kotlin}{Body.satisfy}), die zo de nieuwe goal wordt.
|
|
||||||
Deze procedure wordt herhaald totdat de goal \mintinline{prolog}{true} of \mintinline{prolog}{false} is.
|
\begin{enumerate}
|
||||||
Vervolgens zal het programma backtracken naar de functie die de laatste stap uitvoerde, en de pas geïntroduceerde substituties omhoog doorgeven.
|
\item De databank geeft de goal beurtelings door aan de overeenkomende clauses, aan de hand van \mintinline{kotlin}{solve}.
|
||||||
Daar kan dan logica uitgevoerd worden, of het resultaat verder doorgegeven worden aan de volgende stap.
|
\item Voor elke clause wordt de goal met de head geünificeerd, wat nieuwe substituties kan introduceren.
|
||||||
|
\item De body van de clause wordt geëvalueerd (\mintinline{kotlin}{Body.satisfy}), die zo de nieuwe goal wordt.
|
||||||
|
Deze procedure wordt herhaald totdat de goal \mintinline{prolog}{true} of \mintinline{prolog}{false} is.
|
||||||
|
\item Het programma zal backtracken naar de functie die de laatste stap uitvoerde, en de pas geïntroduceerde substituties omhoog doorgeven.
|
||||||
|
Daar wordt de juiste logica uitgevoerd, of het resultaat wordt verder doorgegeven aan de volgende stap.
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
Doorheen dit proces kunnen variabelen hernoemd worden aan de hand van \mintinline{prolog}{numbervars/1}.
|
||||||
|
Een schematisch overzicht van dit proces is te zien in figuur~\ref{fig:renaming}.
|
||||||
|
|
||||||
% TODO Verklarende figuur met substitutie toevoegen
|
% TODO Verklarende figuur met substitutie toevoegen
|
||||||
|
|
||||||
% Overzicht van geïmplementeerde predicaten in appendix.
|
% Overzicht van geïmplementeerde predicaten in appendix.
|
||||||
Operator-specifieke logica bevindt zich in de klassen van de operatoren zelf.
|
Operator-specifieke logica bevindt zich in de klassen van de operatoren zelf.
|
||||||
|
|
||||||
|
\begin{figure}[H]
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=0.4\textwidth]{renaming}
|
||||||
|
\caption{Voorbeeld van een substitutie met variable renaming.}\label{fig:renaming}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
In de volgende subsecties worden de belangrijkste onderdelen van de evaluatiestrategie in meer detail besproken.
|
||||||
|
|
||||||
\subsection{Unificatie}\label{subsec:unificatie}
|
\subsection{Unificatie}\label{subsec:unificatie}
|
||||||
|
|
||||||
Het unificatie-algoritme is gebaseerd op Robinsons Unificatie-algoritme, zoals beschreven door~\cite{boizumault-1993}, met inspiratie van~\cite{russell2016}.
|
Het unificatie-algoritme is gebaseerd op Robinsons Unificatie-algoritme, zoals beschreven door~\cite{boizumault-1993}, met inspiratie van~\cite{russell2016}.
|
||||||
|
@ -119,30 +134,39 @@
|
||||||
\subsection{Cut}\label{subsec:cut}
|
\subsection{Cut}\label{subsec:cut}
|
||||||
|
|
||||||
De cut operator geeft altijd een \mintinline{kotlin}{Result.failure(AppliedCut)} terug wanneer \mintinline{kotlin}{satisfy} wordt opgeroepen.
|
De cut operator geeft altijd een \mintinline{kotlin}{Result.failure(AppliedCut)} terug wanneer \mintinline{kotlin}{satisfy} wordt opgeroepen.
|
||||||
Deze uitzondering moet dan afgehandeld worden door de aanroepende functie.
|
Deze uitzondering moet dan afgehandeld worden door de aanroepende functie, wat meestal resulteert in het teruggeven van de eerstvolgende oplossing en het onderbreken van de logica.
|
||||||
|
|
||||||
\subsection{Meta abstracties}\label{subsec:meta-abstractions}
|
\subsection{Meta abstracties}\label{subsec:meta-abstractions}
|
||||||
|
|
||||||
|
% KERN: Wat wordt ondersteund?
|
||||||
|
Ghent Prolog ondersteunt meta abstracts zoals \mintinline{prolog}{functor/3}, \mintinline{prolog}{arg/3}, \mintinline{prolog}{=../2} en \mintinline{prolog}{clause/2}.
|
||||||
|
Daarnaast werden ook de operatoren \mintinline{prolog}{reset/3} en \mintinline{prolog}{shift/1} ingebouwd.
|
||||||
|
Die laten toe om \textit{delimited continuations} te gebruiken.
|
||||||
|
|
||||||
|
% KERN: Hoe wordt dat ondersteund?
|
||||||
|
De ingebouwde ondersteuning van delimited continuations maakt opnieuw gebruik vaan een uitzondering.
|
||||||
|
Deze keer heet die \mintinline{kotlin}{Result.failure(AppliedShift)}, die de nieuwe substituties, doorgespeeld term (\textit{ball}) en de nieuwe \textit{continuatie}.
|
||||||
|
Net zoals bij de cut operator, moet deze uitzondering afgehandeld worden door de aanroepende functie.
|
||||||
|
In dit geval zal de \mintinline{kotlin}{AppliedShift} steeds doorgespeeld worden, totdat de \mintlinline{kotlin}{Reset} de uitzondering opvangt.
|
||||||
|
Daarna gaat het programma verder met de nieuwe substituties en continuatie.
|
||||||
|
|
||||||
|
|
||||||
\section{Resultaat}\label{sec:resultaat}
|
\section{Resultaat}\label{sec:resultaat}
|
||||||
|
|
||||||
De implementatie van Ghent Prolog ondersteunt de gevraagde functionaliteit, waaronder database operaties, meta abstracties.
|
De implementatie van Ghent Prolog ondersteunt de gevraagde functionaliteit, waaronder database operaties en meta abstracties.
|
||||||
De architecturele verschillen met SWI-Prolog zijn echter groot, wat zowel positieve als negatieve gevolgen heeft.
|
De architecturele verschillen met SWI-Prolog zijn echter groot, wat zowel positieve als negatieve gevolgen heeft.
|
||||||
|
|
||||||
\subsection{Voordelen}\label{subsec:voordelen}
|
% KERN: Uitbreidbaarheid
|
||||||
|
\textbf{De architectuur van Ghent Prolog is modulair en uitbreidbaar.}
|
||||||
De architectuur van Ghent Prolog is modulair en uitbreidbaar.
|
|
||||||
Eens de evaluatiestrategie en datastructuren zijn gedefinieerd, is het eenvoudig om extra ingebouwde operatoren toe te voegen.
|
Eens de evaluatiestrategie en datastructuren zijn gedefinieerd, is het eenvoudig om extra ingebouwde operatoren toe te voegen.
|
||||||
|
Een volledig overzicht van de geïmplementeerde predicaten, waaronder extra's en uitbreidingen, kan teruggevonden worden in sectie~\ref{sec:predicaten}.
|
||||||
Een volledig overzicht van de geïmplementeerde predicaten kan teruggevonden worden in sectie~\ref{sec:predicaten}.
|
|
||||||
|
|
||||||
\subsection{Uitdagingen}\label{subsec:uitdagingen}
|
|
||||||
|
|
||||||
% KERN: Nesting probleem
|
% KERN: Nesting probleem
|
||||||
\textbf{Code wordt snel onoverzichtelijk} door het gebruik van \texttt{Sequence} en \texttt{Result}.
|
\textbf{Code wordt snel onoverzichtelijk} door het gebruik van \mintinline{kotlin}{Sequence} en \mintinline{kotlin}{Result}.
|
||||||
Belangrijke logica zit genest in onduidelijke boilerplate.
|
Belangrijke logica zit genest in onduidelijke boilerplate.
|
||||||
Volgende code komt bijvoorbeeld in de meeste termen voor, weliswaar in verschillende vorm:
|
De code in~\ref{lst:nesting} komt bijvoorbeeld in de meeste termen voor, weliswaar in verschillende vorm.
|
||||||
|
|
||||||
|
\begin{listing}[H]
|
||||||
\begin{minted}{kotlin}
|
\begin{minted}{kotlin}
|
||||||
/* Function entry logic */
|
/* Function entry logic */
|
||||||
unifyLazy(a, b, subs).forEach { firstResult ->
|
unifyLazy(a, b, subs).forEach { firstResult ->
|
||||||
|
@ -153,58 +177,112 @@
|
||||||
onSuccess = { secondSubs ->
|
onSuccess = { secondSubs ->
|
||||||
/* End result logic */
|
/* End result logic */
|
||||||
yield(Result.success(firstSubs + secondSubs))
|
yield(Result.success(firstSubs + secondSubs))
|
||||||
}
|
},
|
||||||
onFailure = { failure ->
|
onFailure = { failure ->
|
||||||
when (failure) {
|
when (failure) {
|
||||||
is AppliedCut -> /* Cut logic */
|
is AppliedCut -> /* Cut logic */
|
||||||
is AppliedShift -> /* Shift logic */
|
is AppliedShift -> /* Shift logic */
|
||||||
} } ) } } }
|
} } ) } } }
|
||||||
\end{minted}
|
\end{minted}
|
||||||
|
\caption{Voorbeeld van geneste boilerplate code}\label{lst:nesting}
|
||||||
|
\end{listing}
|
||||||
|
|
||||||
% KERN: Overerving zorgt voor boilerplate
|
% KERN: Overerving zorgt voor boilerplate
|
||||||
\textbf{De implementatie bevat boilerplate code} door het gebruik van overerving en interfaces in de klassenrepresentatie van termen.
|
\textbf{De implementatie bevat boilerplate code} door het gebruik van overerving en interfaces in de klassenrepresentatie van termen.
|
||||||
Deze methode wordt gebruikt om de onderlinge relaties tussen de verschillende termen te beschrijven.
|
Deze methode wordt gebruikt om de onderlinge relaties tussen de verschillende termen te beschrijven.
|
||||||
Hoewel nuttig voor de representatie van de AST en generieke functies, moeten de meeste klassen de \texttt{satsify} en \texttt{solve} methoden overschrijven.
|
Hoewel nuttig voor de representatie van de AST en generieke functies, moeten de meeste klassen de \mintinline{kotlin}{satsify} en \mintinline{kotlin}{solve} methoden overschrijven.
|
||||||
Dit zorgt voor boilerplate code en verpreid de logica over verschillende klassen.
|
Dit zorgt voor boilerplate code en verspreidt de logica over verschillende klassen.
|
||||||
Daarnaast kan het leiden tot verlies van type-informatie wanneer generieke functies en type-specifieke functies worden gemengd.
|
Daarnaast kan het leiden tot verlies van type-informatie wanneer generieke functies en type-specifieke functies worden gemengd.
|
||||||
|
|
||||||
\subsection{Functionele afwijkingen van SWI-Prolog}\label{subsec:afwijkingen}
|
\subsection{Functionele afwijkingen van SWI-Prolog}\label{subsec:afwijkingen}
|
||||||
% TODO Maak appendix?
|
% TODO Maak appendix?
|
||||||
|
|
||||||
|
% KERN: Functionele afwijkingen
|
||||||
|
De huidige versie van Ghent Prolog heeft functionele afwijkingen van SWI-Prolog:
|
||||||
|
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item Door het gebruik van de \textit{occurs check} is het niet mogelijk om een oplossing te vinden voor recursieve unificatie.
|
\item Door het gebruik van de \textit{occurs check} is het niet mogelijk om een oplossing te vinden voor recursieve unificatie.
|
||||||
Voor \mintinline{prolog}{?- X = f(X).} vindt SWI-Prolog de oplossing \mintinline{prolog}{X = f(f(X))}, maar Ghent Prolog geeft \texttt{false} terug.
|
Voor \mintinline{prolog}{?- X = f(X).} vindt SWI-Prolog de oplossing \mintinline{prolog}{X = f(f(X))}, maar Ghent Prolog geeft \texttt{false} terug.
|
||||||
\item ISO Prolog en SWI-Prolog maken gebruik van SLD-resolutie
|
\item Ghent Prolog maakt geen gebruik van SLD-resolutie, in tegenstelling tot ISO Prolog en SWI-Prolog (\cite{toman-2008}).
|
||||||
% TODO Bron
|
\item In de REPL wordt er niet meteen teruggekeerd naar de prompt als een query maar één oplossing heeft.
|
||||||
|
Dit is een artifact om oplossingen die de database aanpassen, bijvoorbeeld \mintinline{prolog}{retract/1}, pas uit te voeren wanneer de gebruiker dat expliciet vraagt.
|
||||||
|
Het gebruik van een iterator en \mintinline{kotlin}{it.hasNext()} zou al de volgende oplossing genereren.
|
||||||
|
|
||||||
|
Verder wordt ook de puntkomma (\texttt{;}) pas herkend na een newline.
|
||||||
|
\item Voorlopig is het niet mogelijk om ingebouwde operatoren te overschrijven met \mintinline{prolog}{assert/1} of \mintinline{prolog}{retract/1}.
|
||||||
|
Dit is een gevolg van het gebruik van de preprocessor.
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
|
||||||
% Occurs check
|
|
||||||
|
|
||||||
% SLD Resolutie
|
|
||||||
In tegenstelling tot ISO Prolog en SWI-Prolog, maak ik geen gebruik van SLD-resolutie.
|
|
||||||
% TODO Bronnen voor SLD-resolutie
|
|
||||||
% TODO Bronnen voor ISO-Prolog maakt gebruik van SLD resolutie
|
|
||||||
% TODO Bronnen voor SWIPL maakt gebruik van SLD resolutie
|
|
||||||
|
|
||||||
|
|
||||||
\section{Toekomstig werk}\label{sec:toekomstig-werk}
|
\section{Toekomstig werk}\label{sec:toekomstig-werk}
|
||||||
|
|
||||||
|
% KERN: Wat moet volgende keer anders?
|
||||||
|
Bij de ontwikkeling van een variant van Ghent Prolog, wordt er best aandacht besteed aan de volgende zaken:
|
||||||
|
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item Het gebruik van een stack voor choicepoints en andere informatie om het gebruik van exceptions weg te werken en eenvoudiger choicepoints te kunnen manipuleren.
|
\item Het gebruik van een stack voor choicepoints en andere informatie om het gebruik van exceptions weg te werken en eenvoudiger choicepoints te kunnen manipuleren.
|
||||||
Zo kan bijvoorbeeld de cut operator transparanter \textit{committen} tot de huidige oplossing door in één stap de juiste choicepoints te verwijderen, zonder dat elke operator een \texttt{AppliedCut} moet afhandelen.
|
Zo kan bijvoorbeeld de cut operator transparanter \textit{committen} tot de huidige oplossing door in één stap de juiste choicepoints te verwijderen, zonder dat elke operator een \texttt{AppliedCut} moet afhandelen.
|
||||||
\item Het gebruik van een visitor-patroon in plaats van overerving, om boilerplate te verminderen, zoals aangegeven in sectie~\ref{subsec:uitdagingen}.
|
\item Het gebruik van een visitor-patroon in plaats van overerving, om boilerplate te verminderen, zoals aangegeven in sectie~\ref{sec:resultaat}.
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
|
||||||
|
|
||||||
\section{Conclusie}\label{sec:conclusie}
|
\section{Conclusie}\label{sec:conclusie}
|
||||||
|
|
||||||
|
% KERN: Niet equivalent.
|
||||||
|
Ghent Prolog is duidelijk een proof of concept project.
|
||||||
|
Het kan nog lang niet als equivalent van SWI-Prolog beschouwd worden.
|
||||||
|
|
||||||
|
% KERN: Wat heb ik eruit gehaald?
|
||||||
|
Het implementeren ervan en het onderzoeken van de (voorlopig) ingebouwde functionaliteit biedt echter een goed inzicht in de werking van Prolog.
|
||||||
|
Het geeft een beter begrip van de ingebouwde operatoren en hoe die interageren.
|
||||||
|
|
||||||
|
Persoonlijk vond ik de moeilijkste stap het opzetten van de evaluatie-strategie.
|
||||||
|
Daarna ging het toevoegen van extra operatoren en functionaliteit vrij vlot.
|
||||||
|
Ik ben ondertussen bezig met het zoeken van een manier om een bronbestand te schrijven waarmee de som van de getallen in een interval berekend wordt, aan de hand van \mintinline{prolog}{read/1}, \mintinline{prolog}{between/3} en delimited continuations.
|
||||||
|
|
||||||
\printbibliography
|
\printbibliography
|
||||||
|
|
||||||
\appendix
|
\appendix
|
||||||
\newpage
|
\newpage
|
||||||
|
|
||||||
|
|
||||||
|
\section{Lexing, parsing en preprocessing}\label{sec:lexing-parsing-preprocessing}
|
||||||
|
|
||||||
|
% KERN: Overzicht
|
||||||
|
Traditioneel zijn de lexer en parser aparte componenten.
|
||||||
|
Om tijd te besparen werd echter voor het lexen en parsen van Prolog broncode en REPL-invoer gebruik gemaakt van de \texttt{better-parse} bibliotheek.
|
||||||
|
Een gecompartimentaliseerde, onafgewerkt variant wordt besproken in sectie~\ref{subsec:onafgewerkte-lexer-parser}.
|
||||||
|
|
||||||
|
% KERN: Grammatica
|
||||||
|
De parser maakt gebruik van een vereenvoudigde Prolog grammatica, gebaseerd op
|
||||||
|
\href{https://github.com/antlr/grammars-v4/blob/master/prolog/prolog.g4}{de ANTLR Prolog grammatica},
|
||||||
|
\href{https://sicstus.sics.se/sicstus/docs/3.7.1/html/sicstus_45.html#SEC370}{SICStus Prolog Full Prolog Syntax} en
|
||||||
|
\href{https://github.com/simonkrenger/ch.bfh.bti7064.w2013.PrologParser/blob/2c06e5a221c1cc51ba766304250749a7f0caed8c/doc/prolog-bnf-grammar.txt}{simonkrenger/PrologParser's BNF}.
|
||||||
|
De uiteindelijk gebruikte grammatica kan teruggevonden worden in de \texttt{parser/grammars}.
|
||||||
|
|
||||||
|
% KERN: Simpliciteit en preprocessor
|
||||||
|
Omdat de lexer en parser niet op maat gemaakt zijn, worden ze bewust zo eenvoudig mogelijk gehouden.
|
||||||
|
Hun verantwoordelijkheid is het omzetten van inputtekst naar een basis Abstract Syntax Tree (AST), die enkel uit generieke Prolog termen bestaat.
|
||||||
|
Merk op dat de parser ook verantwoordelijk is voor operator precedentie en associativiteit, zoals besproken wordt in sectie~\ref{subsec:operator-precedence}.
|
||||||
|
|
||||||
|
Daarna worden de termen in de AST door de preprocessor omgezet naar specifieke klassen die de ingebouwde operatoren voorstellen.
|
||||||
|
Termen worden herkend aan de hand van hun functor en ariteit.
|
||||||
|
|
||||||
|
Na de preprocessor is de AST klaar om gebruikt te worden door de evaluatie-fase.
|
||||||
|
|
||||||
|
\subsection{Onafgewerkte Lexer en Parser implementatie}\label{subsec:onafgewerkte-lexer-parser}
|
||||||
|
|
||||||
|
% KERN: Introductie vorige implementatie
|
||||||
|
Origineel werden de lexer en parser op maat gemaakt, zonder het gebruik van een parser library.
|
||||||
|
De lexer en parser waren gebaseerd op
|
||||||
|
\href{https://craftinginterpreters.com/contents.html}{Crafting Interpreters, Robert Nystrom} en
|
||||||
|
\href{https://www.youtube.com/playlist?list=PLGNbPb3dQJ_5FTPfFIg28UxuMpu7k0eT4}{Building a Parser from scratch, Dmitry Soshnikov}.
|
||||||
|
De parser was een recursive descent parser.
|
||||||
|
|
||||||
|
De voorlopige implementatie kan nog steeds teruggevonden worden op commit
|
||||||
|
\href{https://github.com/Logisch-Programmeren/project2425-tdpeuter/tree/d5632e92173abf443251d2445de31f03b696b1d0/src}{d5632e9}.
|
||||||
|
|
||||||
|
|
||||||
\section{Aanvullende opmerkingen}\label{sec:aanvullende-opmerkingen}
|
\section{Aanvullende opmerkingen}\label{sec:aanvullende-opmerkingen}
|
||||||
|
|
||||||
\subsection{Operator precedentie en associativiteit}\label{subsec:operator-precedence}
|
\subsection{Operator precedentie en associativiteit}\label{subsec:operator-precedence}
|
||||||
|
@ -212,45 +290,32 @@
|
||||||
Ghent Prolog ondersteunt operator precedentie en associativiteit.
|
Ghent Prolog ondersteunt operator precedentie en associativiteit.
|
||||||
Deze functionaliteit bevindt zich in de parser, omdat de argumenten van een operator steeds rechtstreeks als parameters in de constructor van de klasse worden meegegeven.
|
Deze functionaliteit bevindt zich in de parser, omdat de argumenten van een operator steeds rechtstreeks als parameters in de constructor van de klasse worden meegegeven.
|
||||||
|
|
||||||
Operator precedentie en associativiteit werd geïmplementeerd volgens de \href{https://www.swi-prolog.org/pldoc/man?section=operators}{SWI-Prolog documentatie}.
|
Operator precedentie en associativiteit werd geïmplementeerd volgens de~\href{https://www.swi-prolog.org/pldoc/man?section=operators}{SWI-Prolog documentatie}.
|
||||||
|
|
||||||
|
\subsection{Database bewerkingen}\label{subsec:database}
|
||||||
|
|
||||||
|
Ghent Prolog laat toe om tijdens de programma-uitvoering database bestanden te laden met behulp van de \mintinline{prolog}{consult/1} predicaat.
|
||||||
|
|
||||||
|
De ingeladen predicaten worden als \mintinline{prolog}{static} gemarkeerd, maar kunnen \mintinline{prolog}{dynamic} worden met behulp van het \mintinline{prolog}{dynamic/1} predicaat.
|
||||||
|
Dit is analoog aan SWI-Prolog.
|
||||||
|
|
||||||
\subsection{Test driven development}\label{subsec:ttd}
|
\subsection{Test driven development}\label{subsec:ttd}
|
||||||
|
|
||||||
Doorheen de ontwikkeling van grote delen van mijn implementatie heb ik gebruik gemaakt van Test Driven Development, onder andere met behulp van \href{https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-t-o-d-o.html}{Kotlin \texttt{TODO}}.
|
Doorheen de ontwikkeling van grote delen van mijn implementatie heb ik gebruik gemaakt van Test Driven Development, onder andere met behulp van \href{https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-t-o-d-o.html}{Kotlin \texttt{TODO}}.
|
||||||
|
|
||||||
\subsection{Onafgewerkte Lexer en Parser implementatie}\label{subsec:lexer-parser}
|
|
||||||
|
|
||||||
Bij de start van het project was ik begonnen met het schrijven van mijn eigen lexer en parser.
|
|
||||||
Uit gebruik omdat het eenvoudiger was om de parser library
|
|
||||||
% TODO reference sectie over de parser
|
|
||||||
te gebruiken.
|
|
||||||
|
|
||||||
De implementatie was gebaseerd op \href{https://craftinginterpreters.com/contents.html}{Crafting Interpreters, Robert Nystrom} en \href{https://www.youtube.com/playlist?list=PLGNbPb3dQJ_5FTPfFIg28UxuMpu7k0eT4}{Building a Parser from scratch, Dmitry Soshnikov}.
|
|
||||||
|
|
||||||
De voorlopige implementatie van de lexer en parser kunnen hier teruggevonden worden.
|
|
||||||
% TODO Link naar commit met voorlopige implementatie
|
|
||||||
|
|
||||||
|
|
||||||
\section{Uitvoeren en testen}\label{sec:uitvoeren-en-testen}
|
\section{Uitvoeren en testen}\label{sec:uitvoeren-en-testen}
|
||||||
|
|
||||||
Om Ghent Prolog op een Windows, Linux of MacOS uit te voeren is het voldoende om Java te installeren en Ghent Prolog op te roepen met `./src/gpl`.
|
Om Ghent Prolog op een Windows, Linux of MacOS uit te voeren is het voldoende om Java te installeren en Ghent Prolog op te roepen met \texttt{./src/gpl}.
|
||||||
De nodige stappen, waaronder het bouwen van een JAR, worden dan automatisch uitgevoerd.
|
De nodige stappen, waaronder het bouwen van een JAR, worden dan automatisch uitgevoerd.
|
||||||
|
|
||||||
De ingediende JAR kan ook handmatig opgeroepen worden met \texttt{java -jar ./build/gpl.jar}.
|
De ingediende JAR kan ook handmatig opgeroepen worden met \texttt{java -jar ./build/gpl.jar}.
|
||||||
|
|
||||||
Er wordt ook een Docker omgeving voorzien waarin Ghent Prolog opgeroepen kan worden met \texttt{gpl}.
|
|
||||||
|
|
||||||
Het programma ondersteunt de volgende vlaggen:
|
|
||||||
|
|
||||||
% TODO gpl --help
|
|
||||||
|
|
||||||
\subsection{Testen}\label{subsec:testen}
|
\subsection{Testen}\label{subsec:testen}
|
||||||
|
|
||||||
De testen kunnen uitgevoerd worden door de meeste IDE's.
|
De testen kunnen uitgevoerd worden door de meeste IDE's.
|
||||||
|
|
||||||
Alternatief kunnen de testen uitgevoerd worden met \texttt{./gradlew test}.
|
Alternatief kunnen de testen uitgevoerd worden met \texttt{./gradlew test}.
|
||||||
Resultaten worden naar \texttt{stdout} geschreven of kunnen bekeken worden met
|
|
||||||
% TODO HTML rapporten.
|
|
||||||
|
|
||||||
|
|
||||||
\section{Overzicht van geïmplementeerde predicaten}\label{sec:predicaten}
|
\section{Overzicht van geïmplementeerde predicaten}\label{sec:predicaten}
|
||||||
|
@ -265,7 +330,7 @@
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item \texttt{functor/3}
|
\item \texttt{functor/3}
|
||||||
\item \texttt{arg/3}
|
\item \texttt{arg/3}
|
||||||
\item \texttt{=..}
|
\item \texttt{=../2}
|
||||||
\item \texttt{numbervars/1}
|
\item \texttt{numbervars/1}
|
||||||
\item \texttt{numbervars/3}
|
\item \texttt{numbervars/3}
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
@ -366,10 +431,14 @@
|
||||||
Vaak zijn deze implementaties niet meer dan een proof of concept.
|
Vaak zijn deze implementaties niet meer dan een proof of concept.
|
||||||
Ze waren enkel nuttig als inspiratie om specifieke problemen die zich tijdens de ontwikkeling van Ghent Prolog voordeden op te lossen.
|
Ze waren enkel nuttig als inspiratie om specifieke problemen die zich tijdens de ontwikkeling van Ghent Prolog voordeden op te lossen.
|
||||||
|
|
||||||
|
Voorbeelden van zulke implementaties zijn:
|
||||||
|
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item \href{https://github.com/adamjstewart/prolog}{adamjstewart/prolog}, in OCaml
|
\item \href{https://github.com/adamjstewart/prolog}{adamjstewart/prolog}, in OCaml
|
||||||
\item \href{https://plzoo.andrej.com/language/miniprolog.html}{miniprolog}, in OCaml
|
\item \href{https://plzoo.andrej.com/language/miniprolog.html}{miniprolog}, in OCaml
|
||||||
\item \href{https://github.com/benjamin-hodgson/Amateurlog}{benjamin-hodgson/Amateurlog}, in C\#
|
\item \href{https://github.com/benjamin-hodgson/Amateurlog}{benjamin-hodgson/Amateurlog}, in C\#
|
||||||
|
\item \href{https://github.com/fmidue/prolog}{fmidue/prolog}, in Haskell
|
||||||
|
\item \href{https://github.com/patirasam/Prolog-Interpreter}{patirasam/Prolog-Interpreter}, in Python
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
|
||||||
Van de implementaties die wel vermeld worden in~\cite{enwiki:1274527056}, zijn
|
Van de implementaties die wel vermeld worden in~\cite{enwiki:1274527056}, zijn
|
||||||
|
|
22
examples/basics/summer.pl
Normal file
22
examples/basics/summer.pl
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
summer(Start, End, 0) :- Start == End.
|
||||||
|
summer(Start, End, Sum) :-
|
||||||
|
Start \== End,
|
||||||
|
Next is Start + 1,
|
||||||
|
summer(Next, End, Rest),
|
||||||
|
writeln(rest(Rest)),
|
||||||
|
Sum is Start + Rest,
|
||||||
|
writeln(sum(Sum)).
|
||||||
|
|
||||||
|
my_sum :-
|
||||||
|
write('Enter start: '),
|
||||||
|
read(Start),
|
||||||
|
write('Enter end: '),
|
||||||
|
read(End),
|
||||||
|
summer(Start, End, Sum),
|
||||||
|
write('The sum is: '),
|
||||||
|
write(Sum), nl.
|
||||||
|
|
||||||
|
main :-
|
||||||
|
summer(1, 5, Sum).
|
||||||
|
|
||||||
|
:- initialization(main).
|
15
examples/meta/ceremony.pl
Normal file
15
examples/meta/ceremony.pl
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
printer :-
|
||||||
|
writeln("Good evening everyone!"),
|
||||||
|
write("Thanks for coming "),
|
||||||
|
shift(Name),
|
||||||
|
write(Name), write(", ").
|
||||||
|
|
||||||
|
main :-
|
||||||
|
writeln("/Ceremony starts/"),
|
||||||
|
reset(printer, Name, Cont),
|
||||||
|
\+ \+ ( Name = "John", call(Cont) ),
|
||||||
|
\+ \+ ( Name = "Mary", call(Cont) ),
|
||||||
|
writeln("and my parents!"),
|
||||||
|
writeln("/Ceremony ends/").
|
||||||
|
|
||||||
|
:- initialization(main).
|
|
@ -3,8 +3,9 @@ package prolog.ast.arithmetic
|
||||||
import prolog.Answers
|
import prolog.Answers
|
||||||
import prolog.Substitutions
|
import prolog.Substitutions
|
||||||
import prolog.ast.logic.LogicOperand
|
import prolog.ast.logic.LogicOperand
|
||||||
|
import prolog.ast.terms.Body
|
||||||
|
|
||||||
data class Integer(override val value: Int) : Number, LogicOperand() {
|
data class Integer(override val value: Int) : Number, Body, LogicOperand() {
|
||||||
// Integers are already evaluated
|
// Integers are already evaluated
|
||||||
override fun simplify(subs: Substitutions): Simplification = Simplification(this, this)
|
override fun simplify(subs: Substitutions): Simplification = Simplification(this, this)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package prolog.ast.terms
|
package prolog.ast.terms
|
||||||
|
|
||||||
|
import prolog.Substitutions
|
||||||
import prolog.ast.logic.Satisfiable
|
import prolog.ast.logic.Satisfiable
|
||||||
|
|
||||||
interface Body : Term, Satisfiable
|
interface Body : Term, Satisfiable {
|
||||||
|
override fun applySubstitution(subs: Substitutions): Body
|
||||||
|
}
|
||||||
|
|
|
@ -40,8 +40,8 @@ class EvaluatesToDifferent(private val left: Expression, private val right: Expr
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun applySubstitution(subs: Substitutions): EvaluatesToDifferent = EvaluatesToDifferent(
|
override fun applySubstitution(subs: Substitutions): EvaluatesToDifferent = EvaluatesToDifferent(
|
||||||
left.applySubstitution(subs) as Expression,
|
applySubstitution(left, subs),
|
||||||
right.applySubstitution(subs) as Expression
|
applySubstitution(right, subs)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,8 +63,8 @@ class EvaluatesTo(private val left: Expression, private val right: Expression) :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun applySubstitution(subs: Substitutions): EvaluatesTo = EvaluatesTo(
|
override fun applySubstitution(subs: Substitutions): EvaluatesTo = EvaluatesTo(
|
||||||
left.applySubstitution(subs) as Expression,
|
applySubstitution(left, subs),
|
||||||
right.applySubstitution(subs) as Expression
|
applySubstitution(right, subs)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,8 +89,8 @@ class Is(val number: Expression, val expr: Expression) :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun applySubstitution(subs: Substitutions): Is = Is(
|
override fun applySubstitution(subs: Substitutions): Is = Is(
|
||||||
number.applySubstitution(subs) as Expression,
|
applySubstitution(number, subs),
|
||||||
expr.applySubstitution(subs) as Expression
|
applySubstitution(expr, subs)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,8 +117,8 @@ open class Add(private val expr1: Expression, private val expr2: Expression) :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun applySubstitution(subs: Substitutions): Add = Add(
|
override fun applySubstitution(subs: Substitutions): Add = Add(
|
||||||
expr1.applySubstitution(subs) as Expression,
|
applySubstitution(expr1, subs),
|
||||||
expr2.applySubstitution(subs) as Expression
|
applySubstitution(expr2, subs)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,8 +140,8 @@ open class Subtract(private val expr1: Expression, private val expr2: Expression
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun applySubstitution(subs: Substitutions): Subtract = Subtract(
|
override fun applySubstitution(subs: Substitutions): Subtract = Subtract(
|
||||||
expr1.applySubstitution(subs) as Expression,
|
applySubstitution(expr1, subs),
|
||||||
expr2.applySubstitution(subs) as Expression
|
applySubstitution(expr2, subs)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,8 +158,8 @@ class Multiply(val expr1: Expression, val expr2: Expression) :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun applySubstitution(subs: Substitutions): Multiply = Multiply(
|
override fun applySubstitution(subs: Substitutions): Multiply = Multiply(
|
||||||
expr1.applySubstitution(subs) as Expression,
|
applySubstitution(expr1, subs),
|
||||||
expr2.applySubstitution(subs) as Expression
|
applySubstitution(expr2, subs)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,8 +173,8 @@ class Divide(private val expr1: Expression, private val expr2: Expression) :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun applySubstitution(subs: Substitutions): Divide = Divide(
|
override fun applySubstitution(subs: Substitutions): Divide = Divide(
|
||||||
expr1.applySubstitution(subs) as Expression,
|
applySubstitution(expr1, subs),
|
||||||
expr2.applySubstitution(subs) as Expression
|
applySubstitution(expr2, subs)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,9 +206,9 @@ class Between(private val expr1: Expression, private val expr2: Expression, priv
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun applySubstitution(subs: Substitutions): Between = Between(
|
override fun applySubstitution(subs: Substitutions): Between = Between(
|
||||||
expr1.applySubstitution(subs) as Expression,
|
applySubstitution(expr1, subs),
|
||||||
expr2.applySubstitution(subs) as Expression,
|
applySubstitution(expr2, subs),
|
||||||
expr3.applySubstitution(subs) as Expression
|
applySubstitution(expr3, subs)
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun toString(): String = "$expr1..$expr3..$expr2"
|
override fun toString(): String = "$expr1..$expr3..$expr2"
|
||||||
|
|
|
@ -55,7 +55,7 @@ open class Conjunction(val left: LogicOperand, private val right: LogicOperand)
|
||||||
right.fold(
|
right.fold(
|
||||||
// If the right part succeeds, yield the result with the left substitutions
|
// If the right part succeeds, yield the result with the left substitutions
|
||||||
onSuccess = { rightSubs ->
|
onSuccess = { rightSubs ->
|
||||||
yield(Result.success(leftSubs + rightSubs))
|
yield(Result.success(rightSubs + leftSubs))
|
||||||
},
|
},
|
||||||
onFailure = { exception ->
|
onFailure = { exception ->
|
||||||
// If the right part fails, check if it's a cut
|
// If the right part fails, check if it's a cut
|
||||||
|
@ -74,8 +74,8 @@ open class Conjunction(val left: LogicOperand, private val right: LogicOperand)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findNextCutSolution(appliedCut: AppliedCut): Answers = sequence {
|
fun findNextCutSolution(appliedCut: AppliedCut): Answers = sequence {
|
||||||
val leftSubs = appliedCut.subs
|
val leftSubs = appliedCut.subs ?: emptyMap()
|
||||||
right.satisfy(subs + (appliedCut.subs!!)).firstOrNull()?.map { rightSubs ->
|
right.satisfy(subs + leftSubs).firstOrNull()?.map { rightSubs ->
|
||||||
// If the right part succeeds, yield the result with the left substitutions
|
// If the right part succeeds, yield the result with the left substitutions
|
||||||
yield(Result.success(leftSubs + rightSubs))
|
yield(Result.success(leftSubs + rightSubs))
|
||||||
return@sequence
|
return@sequence
|
||||||
|
|
|
@ -27,7 +27,7 @@ class Examples {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun debugHelper() {
|
fun debugHelper() {
|
||||||
loader.load("examples/meta/continuations.pl")
|
loader.load("examples/basics/summer.pl")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
|
@ -60,11 +60,13 @@ class Examples {
|
||||||
Arguments.of("forall.pl", "Only alice likes pizza.\n"),
|
Arguments.of("forall.pl", "Only alice likes pizza.\n"),
|
||||||
Arguments.of("fraternity.pl", "Citizen robespierre is eligible for the event.\nCitizen danton is eligible for the event.\nCitizen camus is eligible for the event.\n"),
|
Arguments.of("fraternity.pl", "Citizen robespierre is eligible for the event.\nCitizen danton is eligible for the event.\nCitizen camus is eligible for the event.\n"),
|
||||||
Arguments.of("liberty.pl", "Give me Liberty, or give me Death!\nI disapprove of what you say, but I will defend to the death your right to say it.\nThe revolution devours its own children.\nSo this is how liberty dies, with thunderous applause.\n"),
|
Arguments.of("liberty.pl", "Give me Liberty, or give me Death!\nI disapprove of what you say, but I will defend to the death your right to say it.\nThe revolution devours its own children.\nSo this is how liberty dies, with thunderous applause.\n"),
|
||||||
|
Arguments.of("summer.pl", "rest(0)\nsum(4)\nrest(4)\nsum(7)\nrest(7)\nsum(9)\nrest(9)\nsum(10)\n"),
|
||||||
Arguments.of("unification.pl", "While alice got an A, carol got an A, but bob did not get an A, dave did not get an A, unfortunately.\n"),
|
Arguments.of("unification.pl", "While alice got an A, carol got an A, but bob did not get an A, dave did not get an A, unfortunately.\n"),
|
||||||
Arguments.of("write.pl", "gpl zegt: dag(wereld)\n"),
|
Arguments.of("write.pl", "gpl zegt: dag(wereld)\n"),
|
||||||
)
|
)
|
||||||
|
|
||||||
fun meta() = listOf(
|
fun meta() = listOf(
|
||||||
|
Arguments.of("ceremony.pl", "/Ceremony starts/\nGood evening everyone!\nThanks for coming John, Mary, and my parents!\n/Ceremony ends/\n"),
|
||||||
Arguments.of("continuations.pl", "Inside test\nEntering reset\nAfter reset\nCalling Cont(2)\nIn test X = 5; done\nCalling Cont(4)\nIn test X = 9; done\n"),
|
Arguments.of("continuations.pl", "Inside test\nEntering reset\nAfter reset\nCalling Cont(2)\nIn test X = 5; done\nCalling Cont(4)\nIn test X = 9; done\n"),
|
||||||
Arguments.of("mib_voorbeelden.pl", "b\nf(b)\nf(g(a,a),h(c,d),i(e,f))\nf(g(a,a),h(c,c),i(e,f))\nf(g(a,a),h(c,c),i(e,e))\n")
|
Arguments.of("mib_voorbeelden.pl", "b\nf(b)\nf(g(a,a),h(c,d),i(e,f))\nf(g(a,a),h(c,c),i(e,f))\nf(g(a,a),h(c,c),i(e,e))\n")
|
||||||
)
|
)
|
||||||
|
|
Reference in a new issue