|
|
@ -7,11 +7,9 @@
|
|
|
|
\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{float} % Figures
|
|
|
|
\usepackage[margin=1in]{geometry} % Sane marges
|
|
|
|
\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
|
|
|
|
|
|
|
|
|
|
|
@ -28,18 +26,14 @@
|
|
|
|
% 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.
|
|
|
@ -48,19 +42,27 @@
|
|
|
|
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.
|
|
|
|
|
|
|
|
Voor meer informatie over de lexing en parsing, zie sectie~\ref{sec:lexing-parsing-preprocessing}.
|
|
|
|
\section{Lexing, parsing en preprocessing}\label{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 en streams om een backtracking mechanisme te implementeren.
|
|
|
|
Ghent Prolog maakt gebruik van functie-oproepen streams om het backtracking mechanisme te implementeren.
|
|
|
|
Bijzondere logica met betrekking tot \textit{choicepoints} en foutenafhandeling maakt gebruik van de Kotlin \mintinline{kotlin}{Result} klasse.
|
|
|
|
Bijzondere logica met betrekking tot \textit{choicepoints} en foutenafhandeling maakt gebruik van de Kotlin \texttt{Result} klasse.
|
|
|
|
Om de resultaten van unificatie en evaluatie \textit{lazy} te verwerken, wordt er gebruik gemaakt van Kotlin \mintinline{kotlin}{Sequence}'s (\textit{lazy streams}).
|
|
|
|
Om de resultaten van unificatie en evaluatie lazy te verwerken, wordt er gebruik gemaakt van Kotlin \texttt{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:
|
|
|
|
|
|
|
|
|
|
|
@ -93,39 +95,22 @@
|
|
|
|
\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}.
|
|
|
|
Op het moment dat de databank een goal gevraagd wordt (\textit{query}), worden de volgende stappen doorlopen:
|
|
|
|
Eerst wordt de goal met de head van de clause geünificeerd, wat nieuwe substituties kan introduceren.
|
|
|
|
|
|
|
|
Daarna wordt de body van de clause geëvalueerd (\mintinline{kotlin}{Body.satisfy}), die zo de nieuwe goal wordt.
|
|
|
|
\begin{enumerate}
|
|
|
|
Deze procedure wordt herhaald totdat de goal \mintinline{prolog}{true} of \mintinline{prolog}{false} is.
|
|
|
|
\item De databank geeft de goal beurtelings door aan de overeenkomende clauses, aan de hand van \mintinline{kotlin}{solve}.
|
|
|
|
Vervolgens zal het programma backtracken naar de functie die de laatste stap uitvoerde, en de pas geïntroduceerde substituties omhoog doorgeven.
|
|
|
|
\item Voor elke clause wordt de goal met de head geünificeerd, wat nieuwe substituties kan introduceren.
|
|
|
|
Daar kan dan logica uitgevoerd worden, of het resultaat verder doorgegeven worden aan de volgende stap.
|
|
|
|
\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}.
|
|
|
@ -134,39 +119,30 @@
|
|
|
|
\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, wat meestal resulteert in het teruggeven van de eerstvolgende oplossing en het onderbreken van de logica.
|
|
|
|
Deze uitzondering moet dan afgehandeld worden door de aanroepende functie.
|
|
|
|
|
|
|
|
|
|
|
|
\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 en meta abstracties.
|
|
|
|
De implementatie van Ghent Prolog ondersteunt de gevraagde functionaliteit, waaronder database operaties, 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.
|
|
|
|
|
|
|
|
|
|
|
|
% KERN: Uitbreidbaarheid
|
|
|
|
\subsection{Voordelen}\label{subsec:voordelen}
|
|
|
|
\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 \mintinline{kotlin}{Sequence} en \mintinline{kotlin}{Result}.
|
|
|
|
\textbf{Code wordt snel onoverzichtelijk} door het gebruik van \texttt{Sequence} en \texttt{Result}.
|
|
|
|
Belangrijke logica zit genest in onduidelijke boilerplate.
|
|
|
|
Belangrijke logica zit genest in onduidelijke boilerplate.
|
|
|
|
De code in~\ref{lst:nesting} komt bijvoorbeeld in de meeste termen voor, weliswaar in verschillende vorm.
|
|
|
|
Volgende code 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 ->
|
|
|
@ -177,112 +153,58 @@
|
|
|
|
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 \mintinline{kotlin}{satsify} en \mintinline{kotlin}{solve} methoden overschrijven.
|
|
|
|
Hoewel nuttig voor de representatie van de AST en generieke functies, moeten de meeste klassen de \texttt{satsify} en \texttt{solve} methoden overschrijven.
|
|
|
|
Dit zorgt voor boilerplate code en verspreidt de logica over verschillende klassen.
|
|
|
|
Dit zorgt voor boilerplate code en verpreid 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 Ghent Prolog maakt geen gebruik van SLD-resolutie, in tegenstelling tot ISO Prolog en SWI-Prolog (\cite{toman-2008}).
|
|
|
|
\item ISO Prolog en SWI-Prolog maken gebruik van SLD-resolutie
|
|
|
|
\item In de REPL wordt er niet meteen teruggekeerd naar de prompt als een query maar één oplossing heeft.
|
|
|
|
% TODO Bron
|
|
|
|
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{sec:resultaat}.
|
|
|
|
\item Het gebruik van een visitor-patroon in plaats van overerving, om boilerplate te verminderen, zoals aangegeven in sectie~\ref{subsec:uitdagingen}.
|
|
|
|
\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}
|
|
|
@ -290,32 +212,45 @@
|
|
|
|
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 \texttt{./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 `./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}
|
|
|
@ -330,7 +265,7 @@
|
|
|
|
\begin{itemize}
|
|
|
|
\begin{itemize}
|
|
|
|
\item \texttt{functor/3}
|
|
|
|
\item \texttt{functor/3}
|
|
|
|
\item \texttt{arg/3}
|
|
|
|
\item \texttt{arg/3}
|
|
|
|
\item \texttt{=../2}
|
|
|
|
\item \texttt{=..}
|
|
|
|
\item \texttt{numbervars/1}
|
|
|
|
\item \texttt{numbervars/1}
|
|
|
|
\item \texttt{numbervars/3}
|
|
|
|
\item \texttt{numbervars/3}
|
|
|
|
\end{itemize}
|
|
|
|
\end{itemize}
|
|
|
@ -431,14 +366,10 @@
|
|
|
|
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
|
|
|
|