10 minute GUI for your Prolog app
We’ll be using a tiny prolog program that can describe the number of stops on a train route, given an origin and a destination.
All the source code, including the Prolog, is available on GitHub. In the Prolog, suffice to say without reading the code, we have a predicate station/1
that describes station names, and route_length/3
that given an origin and a
destination can tell us the number of stops between them.
Step 1: Get SWI-Prolog Talking to Python
We’re blessed by yuce and contributors here, who provide us with pyswip
, an interface between Python and Swi-Prolog. With a quick pip install pyswip
we can create a
Python program (in a file called trains.py
) that’ll query our Prolog:
#!/usr/bin/env python3
from pyswip import Prolog
swipl = Prolog()
swipl.consult("trains.pl")
STATIONS = [ans["S"] for ans in swipl.query("station(S)")]
def route_length(From, To):
return next(swipl.query(f"route_length({From}, {To}, L)"))["L"]
def main():
for station in STATIONS:
print(station)
print(route_length(STATIONS[0], STATIONS[1]))
if __name__ == "__main__":
main()
So we consult our trains.pl
file, then we use the interface to build a list
of STATIONS
via a query. Then we write a proxy function route_length
that
will query route_length/3
in the forward direction. Finally in main
we use
what we’ve defined so we can observe some output: python trains.py
Step 2: Make a Command Line Application
Let’s turn this into an application, it’ll take two arguements for the origin
and destination stations. Then it’ll print out the route length. To do this we
add another import and change the main
function.
#!/usr/bin/env python3
from argparse import ArgumentParser
from pyswip import Prolog
swipl = Prolog()
swipl.consult("trains.pl")
STATIONS = [ans["S"] for ans in swipl.query("station(S)")]
def route_length(From, To):
return next(swipl.query(f"route_length({From}, {To}, L)"))["L"]
def main():
parser = ArgumentParser(description="Find the length of a route between two stations")
parser.add_argument("-o", "--origin", choices=STATIONS, required=True)
parser.add_argument("-d", "--destination", choices=STATIONS, required=True)
args = parser.parse_args()
print(route_length(args.origin, args.destination))
if __name__ == "__main__":
main()
We’re using part of Python’s standard library to handle parsing command line arguments,
which makes this step relatively simple. Now we run it with python trains.py -o chicago -d denver
Step 3: GUI
Suprisingly the easiest step of all, with a pip install Gooey
. Thanks to chriskiehl and contributors.
All we need to do is add an import and a decorator:
#!/usr/bin/env python3
from argparse import ArgumentParser
from gooey import Gooey
from pyswip import Prolog
swipl = Prolog()
swipl.consult("trains.pl")
STATIONS = [ans["S"] for ans in swipl.query("station(S)")]
def route_length(From, To):
return next(swipl.query(f"route_length({From}, {To}, L)"))["L"]
@Gooey
def main():
parser = ArgumentParser(description="Find the length of a route between two stations")
parser.add_argument("-o", "--origin", choices=STATIONS, required=True)
parser.add_argument("-d", "--destination", choices=STATIONS, required=True)
args = parser.parse_args()
print(route_length(args.origin, args.destination))
if __name__ == "__main__":
main()
This we run with python trains.py
, and we’re done. From SWI-Prolog to a GUI via Python
in less than 10 minutes!