Instructions below are mainly for macOS.
Linux and Windows should operate
the same (exact paths and Terminal prompts may differ) and browser
appearance may be different.
Example: Google Chrome on Ubuntu | Example: Google Chrome on Windows 11 |
---|---|
Make sure swipl (www.swi-prolog.org), a free download, is installed
and accessible using the which command, which inspects your
PATH directory list for executable commands.
As you can see below, the
location of the application varies according to platform.
(To install swipl, see Appendix below.)
(base) ~$ which swipl
/opt/homebrew/bin/swipl # for Apple Silicon macOS
or
/usr/local/bin/swipl # macOS Intel x86or
/usr/bin/swipl # Ubuntu Intel x86On Windows, in PowerShell, we have:
C:\Users\sandiway> Get-Command swipl
CommandType Name
----------- -----
Application swipl.exe # Windows 11 (Intel x86)
$ above is the prompt.
Using the Terminal (or PowerShell in Windows) app, cd
(change) to the directory containing the
Minimalist Machine files,
e.g. for me below ~/work/Machine.
I assume here that Terminal starts up in my home directory ~
(the tilde is the Terminal abbreviation for your home directory).
The file you are reading instructions.html also lives in this directory. Next go to step 0.
Pre-compiled Minimalist Machine (mm) executable files exist for Apple Silicon macOS, Ubuntu and Windows. These are:
mm_as is the precompiled file for Apple Silicon, the arm64
architecture. Make sure you're in a Terminal and at the Machine
folder, use the shell cd (change directory) command if necessary.
(Suggestion: you could also rename mm_as as mm to do
less typing below.)
(base) Machine$ file mm_as mm_as: Mach-O 64-bit executable arm64 (base) Machine$ ./mm_as "Minimalist Machine 2023/8/6" Run start(8010). Then load index.html into browser. ?- start(8010). % Started server at http://localhost:8010/ true. ?- ^D (base) Machine$Do you see the Started server message? If so, go to step 4 below directly.
For experts, dependencies.
(base) Machine$ otool -L mm_as
mm_as:
@rpath/libswipl.9.dylib (compatibility version 9.0.0, current version 9.0.4)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.0.0)
(base) Machine$
mm_linux is the precompiled file for Debian Linux on the x86_64
architecture. Make sure you're in a Terminal and at the Machine
folder, use the shell cd (change directory) command if necessary.
(Suggestion: you could also rename mm_linux as mm to do
less typing below.)
~/Machine$ file mm_linux
mm_linux: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=4c704bd856e681e05b5da1fa41b0a42aa5ab9432, for GNU/Linux 3.2.0, stripped
~/Machine$ ./mm_linux "Minimalist Machine 2023/8/6" Run start(8010). Then load index.html into browser. ?- start(8010). % Started server at http://localhost:8010/ true. ?- Received:run( [[here, d, live, 'v*', [student, who_rel], 'T', c_rel], [english, d, study, 'v*', [student, who_rel], 'T', c_rel], the]). ^D ~/Machine$Do you see the Started server message? If so, go to step 4 below directly.
For experts, dependencies.
~/Machine$ ldd mm_linux
linux-vdso.so.1 (0x00007ffde35a0000)
libswipl.so.9 => /usr/lib/swi-prolog/lib/x86_64-linux/libswipl.so.9 (0x00007f59586f9000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f59584be000)
libtinfo.so.6 => /lib/x86_64-linux-gnu/libtinfo.so.6 (0x00007f595848c000)
libgmp.so.10 => /lib/x86_64-linux-gnu/libgmp.so.10 (0x00007f595840a000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f59583ee000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f5958305000)
/lib64/ld-linux-x86-64.so.2 (0x00007f5958899000)
mm_win is the precompiled file for Windows on the x86_64
architecture. Make sure you're in a PowerShell and in the
Machine directory.
You may be asked to grant access to mm_win. Allow it.
You should only encounter Windows Defender first time around,
after that, mm_win should run normally.
(You can quit Prolog using halt.)
For experts, --foreign=save doesn't seem to work, so the required .dlls are also copied from C:\Program Files\swipl\bin into the Machine directory. These are:
Length Name ------ ---- 27136 crypt.dll 67072 crypto4pl.dll 19456 files.dll 31232 http_stream.dll 16384 json.dll 30720 memfile.dll 15360 readutil.dll 198144 sgml2pl.dll 39936 sha4pl.dll 65024 socket.dll 93696 ssl4pl.dll 27648 time.dll 29184 uri.dll 23040 websocket.dll 125108 zlib1.dll 19968 zlib4pl.dll
If you get an error with the pre-compiled binaries, don't use them. You can do everything manually via Steps 1 through 5 below.
NOTE: only come here if Step 0 doesn't work. These files are loaded by default by mm in Step 0.
The following Prolog files must be present in the directory identified above:
Start Prolog (Terminal or PowerShell command swipl) and load these files at the Prolog prompt (?-). Everything to the right of the prompt is typed.
(The list of files to be loaded is named using list syntax [file,...]. The file extension .pl is omitted by convention.)
(Note all commands at the Prolog prompt (?-) must end in a full stop which you must supply.)
(base) Machine$ swipl Welcome to SWI-Prolog (threaded, 64 bits, version 8.2.4) SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software. Please run ?- license. for legal details. For online help and background, visit https://www.swi-prolog.org For built-in help, use ?- help(Topic). or ?- apropos(Word). ?- [portray, ws_treedraw, core]. true.
Note: these files are loaded by default by mm in Step 0.
Theory and language files must also be present in the Machine directory:
?- [m12, grammar].
true.
At the Prolog prompt, start(port) will initialize the Prolog code and make the system ready to receive instructions from the user interface (see steps 4 and 5). We use port 8010.
?- start(8010). % Started server at http://localhost:8010/ true. ?-
The user interface is coded in html/Javascript and resides in the following file:
(Note: reloading the webpage will refresh the connection. You should see Websocket: 8010 CONNECTED if successfully reconnected. If not, you can terminate Prolog and restart it.)
Many examples are available pre-packaged into sections.
Let's expand section 18 and click on the first example in the table. (The instruction stream, i.e. the middle column, is clickable.)
For convenience, clicking on the 1st example in section 18, you should see run([story, the, tell, 'v*', [boy, who_rel], 'Tpast', c_rel, the]). copied into the Input field. (You can also manually enter a run command here.)
The list [story, the, tell, 'v*', [boy, who_rel], 'Tpast', c_rel, the] is the sole argument to the run command and contains the sequence of heads (defined in grammar.pl that will be Merged.
Next, click Send Command to transmit the run command to the Prolog server running in the Terminal (or PowerShell). In turn, the Prolog server will transmit the sequence of steps required to assemble the parse back to the user interface using a Websocket inteface.
After running the example, at the bottom you should see:
the boy who told the story One derivation found.and directly above the parse:
Notice the list of heads passed to the machine [story, the, tell,
'v*', [boy, who_rel], 'Tpast', c_rel, the] isroughly the
reverse linear order of the frontier of the tree. Note however that
boy has been displaced upwards several times from its original
location. (whorel has been displaced too.) All
moved items have a line drawn through them, e.g. boy. Scrolling
up, you will find a step by step derivation.
Affix-hopping takes place at Spell-out, not in Narrow Syntax. For example, Tpast becomes the -ed suffix on the verb tell.
In the Terminal window, you will see a message indicating the Prolog server received the order to run the example. This is for debugging/informational purposes only. If no message is received, it means the user interface failed to communicate with the server. Restarting the Prolog server from step 1 and refreshing the web page (step 4) will usually fix this problem.
?- start(8010).
% Started server at http://localhost:8010/
true.
?- Received:run([story, the, tell, 'v*', [boy, who_rel], 'Tpast', c_rel, the]).
Other useful information:
Click on Clear Output to remove the step by step derivations
from the user interface. Otherwise, all derivations are kept.
By default, the user interface contains a step by step rolling log of examples tried.
Click on the Connect button first if you are manually typing in run
commands to the Input line and see the socket status as
disconnected, e.g. Websocket: 8010 CONNECTED
... DISCONNECTED. Otherwise the Send Command will not work.
When clicking on examples from the sections, there is no need to do
this, the connection is
automatically primed when the run command is copied to the Input line.
Loading the 10 line file mm.pl into Prolog
loads the non-GUI version of the system.
The file terminal.pl
(highlighted in green below)
replaces ws_treedraw.pl.
As a result of this substitution,
trees are not displayed in the browser, syntactic objects will be printed
as bracketed expressions directly to the terminal instead.
Examples are available in various files defining the predicate stream/2, e.g. dbyp.pl
contains some examples from Chomsky's Derivation By Phase
paper.
Example of starting Prolog and loading the terminal version with an example file.
(base) Machine$ swipl Welcome to SWI-Prolog (threaded, 64 bits, version 9.0.4) SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software. Please run ?- license. for legal details. For online help and background, visit https://www.swi-prolog.org For built-in help, use ?- help(Topic). or ?- apropos(Word). ?- [mm]. Minimalist Machine (command line version) load examples defining stream(EX,[...]), streams(SEC,..) debugging asserts: occ_debug run(EX), run_check(SEC), run_check true. ?- [dbyp]. true.
Let's run example e4iia from dbyp.pl.
?- run(e4iia).
Parameter Setting Description
.. list omitted here for brevity...
Stream:[[prizes!D],[several!case!N],[award],[prt!phi!case],[v~],[there!phi],[Tinf!phi],[likely],[v_be],[T!phi],[c]]
Stack: []
SO: []
Step 1.
Head of stream [prizes!D] is the initial SO
% Initial SO is head of stream
Stream:[[several!case!N],[award],[prt!phi!case],[v~],[there!phi],[Tinf!phi],[likely],[v_be],[T!phi],[c]]
Stack: []
SO: [prizes!D]
Step 2.
Merge [several!case!N] and [prizes!D]
Label from [several!case!N] (syntactic head with an unvalued uF)
Inherit interpretable feature(s) [f(phi,[3,pl,n])] from [prizes!D]
[several!case!N] values D on [prizes!D]
[prizes] values N on [several!case!N]
% Merge stream D with SO
Stream:[[award],[prt!phi!case],[v~],[there!phi],[Tinf!phi],[likely],[v_be],[T!phi],[c]]
Stack: []
SO: [several!case[several][prizes]]
Step 3.
Merge [award] and [several!case[several][prizes]]
Label from [award] (syntactic head merging with a non-head)
Theta-mark [several!case[several][prizes]]
Push [several!case[several][prizes]] (unvalued uF) onto stack
% Theta merge for {V|A}
Stream:[[prt!phi!case],[v~],[there!phi],[Tinf!phi],[likely],[v_be],[T!phi],[c]]
Stack: [[several!case[several][prizes]]]
SO: [award[award][several!case[several][prizes]]]
Step 4.
Merge [prt!phi!case] and [award[award][several!case[several..][prizes..]]]
Label from [prt!phi!case] (syntactic head merging with a non-head)
[several!case[several][prizes]] values uPhi on [prt!phi!case]
Unified case feature on [prt!case] and [several!case[several][prizes]]
% Merge stream v and SO
Stream:[[v~],[there!phi],[Tinf!phi],[likely],[v_be],[T!phi],[c]]
Stack: [[several!case[several][prizes]]]
SO: [prt[prt][award[award][several!case[several][prizes]]]]
Step 5.
Internal merge selected
Merge [prt[prt][award[award..][several..]]] and [several!case[several][prizes]]
Label from [prt[prt][award[award..][several..]]] (edge feature)
% Internal merge for v
Stream:[[v~],[there!phi],[Tinf!phi],[likely],[v_be],[T!phi],[c]]
Stack: [[several!case[several][prizes]]]
SO: [prt[several!case[several][prizes]][prt[prt][award[award][several[several][prizes]]]]]
Step 6.
Merge [v~] and [prt[several!case[several..][prizes..]][prt[prt..][award..]]]
Label from [v~] (syntactic head merging with a non-head)
[v~] checks theta on [several!case[several][prizes]]
% Merge stream v and SO
Stream:[[there!phi],[Tinf!phi],[likely],[v_be],[T!phi],[c]]
Stack: [[several!case[several][prizes]]]
SO: [v~[v~][prt[several!case[several][prizes]][prt[prt][award[award][several[several][prizes]]]]]]
... steps 7 through 13 omitted for brevity ...
Step 14.
Internal merge selected
Merge [T[T][v_be[there..][v_be..]]] and [there]
Label from [T[T][v_be[there..][v_be..]]] (edge feature)
% Internal merge to edge of T
Stream:[[c]]
Stack: [[there],[several[several][prizes]]]
SO: [T[there][T[T][v_be[there][v_be[v_be][likely[likely][Tinf[there][Tinf[Tinf][v~[there][v~[v~][prt[several[several][prizes]][prt[prt][award[award][several[several][prizes]]]]]]]]]]]]]]
Step 15.
Merge [c] and [T[there][T[T..][v_be..]]]
Label from [c] (syntactic head merging with a non-head)
% Merge stream C and SO
Stream:[]
Stack: [[there],[several[several][prizes]]]
SO: [c[c][T[there][T[T][v_be[there][v_be[v_be][likely[likely][Tinf[there][Tinf[Tinf][v~[there][v~[v~][prt[several[several][prizes]][prt[prt][award[award][several[several][prizes]]]]]]]]]]]]]]]
Step 16.
Local Extent boundary at [c[c][T[there..][T..]]]
New boundary (b) marker stacked
% SO mark Local Extent boundary with release
Stream:[]
Stack: [b,[there],[several[several][prizes]]]
SO: [c[c][T[there][T[T][v_be[there][v_be[v_be][likely[likely][Tinf[there][Tinf[Tinf][v~[there][v~[v~][prt[several[several][prizes]][prt[prt][award[award][several[several][prizes]]]]]]]]]]]]]]]
Spell-out:
[c,there,t(pres,[unified(3),pl]),v(v_be),likely,Tinf,v(v~),several,prizes,prt,award] (frontier)
=> [there,-re,be,likely,to,be,several,prizes,-en,award] (after morpheme realization)
=> [there,be,-re,likely,to,be,several,prizes,award,-en] (after affix-hop)
=> [there,be,-re,likely,to,be,several,prizes,award,-en] (morpheme realization, stage 2)
=> [there,are,likely,to,be,several,prizes,awarded]
One derivation found.
Running the same example in the browser interface, you will see the
same steps with all syntactic objects, including the final parse, displayed as trees.
If in the example file, predicate spelled/2 (correct Spell-out for each example) and streams/2 (list of example names) are also defined, the call run_check/1 can be used to batch verify the output of the derivations are correct.
spelled/2, 1st argument the example name, and the 2nd argument the correct word list Spell-out:
spelled(e4iia,[there,are,likely,to,be,several,prizes,awarded]). spelled(e4iib,[several,prizes,are,likely,to,be,awarded]).
streams/2, by convention, 1st argument the name of the examples file, and the 2nd argument a list of examples to be checked:
streams(dbyp,[e4iia,e4iib,e4iiia,e4iiib,e15ii,e16ii,e18a,e18b,e20bi,e20bii,e21b,e22c,e24a,e31a,e31b,e38a,e38d]).
run_check/1, the only argument is the 1st argument of streams/2 above.
?- run_check(dbyp).
Example: e4iia [there,are,likely,to,be,several,prizes,awarded] OK
Example: e4iib [several,prizes,are,likely,to,be,awarded] OK
Example: e4iiia [we,expect,there,to,be,several,prizes,awarded] OK
Example: e4iiib [we,expect,several,prizes,to,be,awarded] OK
Example: e15ii [there,is,likely,to,arrive,a,man] OK
Example: e16ii [we,expect,there,to,arrive,a,man] OK
Example: e18a [there,seem,to,have,been,several,fish,caught] OK
Example: e18b [we,expect,there,to,have,been,several,fish,caught] OK
Example: e20bi [there,were,several,fish,believed,to,have,been,caught] OK
Example: e20bii [we,expected,there,to,have,been,several,fish,believed,to,have,been,caught] OK
Example: e21b [there,is,a,man,expected,to,arrive] OK
Example: e22c [there,was,a,large,book,placed,on,the,table] OK
Example: e22c [there,was,a,large,book,placed,on,the,table] OK
Example: e24a [there,were,several,packages,placed,on,the,table] OK
Example: e24a [there,were,several,packages,placed,on,the,table] OK
Example: e31a [what,are,they,selling,books,about] OK
Example: e31b [what,are,there,books,about,being,sold] OK
Example: e38a [there,are,many,fish,expected,to,be,caught] OK
Example: e38d [many,fish,are,expected,to,be,caught] OK
true.
This section assumes you know the linguistic theory and how to program in the Prolog programming language. Do not go here and modify the theory unless you are competent in both areas. However, you should be able to (carefully) modify grammar.pl to add things like new words.
Debugging is straightforward in the terminal version of the program. Just use Prolog's standard spy/1 and nospy/1 directives to check when predicates are invoked.
Debugging with the browser interface is less simple as a console is
not attached by default. The Prolog attach_console command
should be used inside the run/1 predicate in
core.pl. A separate console will then pop up for the command
line debugger during derivations. This is not the same Terminal as the
one you typed start(8010) on.
(In macOS, this requires the freeware XQuartz, which provides X11
support, to be loaded. Latest version is XQuartz 2.8.5.)
Just uncomment the appropriate line here (remove the
%) and substitute the predicate you want to spy on.
For the change to take place, reload core.pl into the Terminal
window.
(Note: this applies only to the browser version.)
For the terminal version, the
regular terminal is already attached. Just type
spy(predicate/arity) at the Prolog prompt
(?-).
Suppose we uncomment the line highlighted in green above. Then reload the file as shown
below:
? - [core].
true.
?- Received:run([mary, d, see, 'v*', [john, d], 'Tpast', c]).
Next, we click on the example shown in the browser.
Note: to restore normal operation without the debugger, we can comment out the attach_console line and reload core.pl.
Installing SWI-Prolog, a freely available Prolog, on Ubuntu, macOS and Windows covered below.
Also, saving the output of the browser including trees is covered here
We follow the instructions at SWI-Prolog here.
First, open a Terminal window and add the repository.
~$ sudo apt-add-repository ppa:swi-prolog/stable
PPA publishes dbgsym, you may need to include 'main/debug' component
Repository: 'deb https://ppa.launchpadcontent.net/swi-prolog/stable/ubuntu/ jammy main'
Description:
Comprehensive Prolog implementation with extensive libraries and development tools. Primarily targetted at teaching, RDF processing and web-related tasks, such as creating web services or analysing web content.
Official PPAs for SWI-Prolog. See https://www.swi-prolog.org for further information.
More info: https://launchpad.net/~swi-prolog/+archive/ubuntu/stable
Adding repository.
Press [ENTER] to continue or Ctrl-c to cancel.
...
Hit:1 http://archive.ubuntu.com/ubuntu jammy InRelease
Hit:2 http://dl.google.com/linux/chrome/deb stable InRelease
Hit:3 http://archive.ubuntu.com/ubuntu jammy-updates InRelease
Hit:4 http://archive.ubuntu.com/ubuntu jammy-backports InRelease
Hit:5 http://archive.ubuntu.com/ubuntu jammy-security InRelease
Hit:6 https://ppa.launchpadcontent.net/swi-prolog/stable/ubuntu jammy InRelease
Reading package lists... Done
Step 2 is install swipl itself.
~$ sudo apt-get install swi-prolog
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
libbsd-dev libedit-dev libgmp-dev libgmpxx4ldbl libmd-dev libncurses-dev
libncurses6 libncursesw6 libossp-uuid16 libreadline-dev libtinfo6
swi-prolog-nox swi-prolog-x
Suggested packages:
gmp-doc libgmp10-doc libmpfr-dev ncurses-doc uuid readline-doc prolog-el
...
Setting up swi-prolog-nox (9.0.4-2-g8c6867e6f-jammyppa2) ...
update-alternatives: using /usr/bin/swipl to provide /usr/bin/prolog (prolog) in auto mode
Setting up swi-prolog-x (9.0.4-2-g8c6867e6f-jammyppa2) ...
Setting up swi-prolog (9.0.4-2-g8c6867e6f-jammyppa2) ...
Processing triggers for libc-bin (2.35-0ubuntu3.1) ...
Processing triggers for man-db (2.10.2-1) ...
Processing triggers for install-info (6.8-4build1) ...
Step 3 is check swipl has been installed properly. In the
Terminal window, try the following.
(Note: ^D below is Control-D, the end of
file character used to terminate the Prolog session and return to the
Terminal shell.)
~$ which swipl /usr/bin/swipl ~$ swipl Welcome to SWI-Prolog (threaded, 64 bits, version 9.0.4) SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software. Please run ?- license. for legal details. For online help and background, visit https://www.swi-prolog.org For built-in help, use ?- help(Topic). or ?- apropos(Word). ?- ^D % halt ~$
Either go to https://www.swi-prolog.org/download/stable and follow the instructions there, or install brew, the package manager system first, and then the package swipl as follows.
Go to https://brew.sh. It suggests running the following command in a Terminal:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Make sure /opt/homebrew/bin is on your PATH of executables.
$ echo $PATH
... /opt/homebrew/bin: ...
If not, add it to your ~/.bash_profile Terminal startup file,
a snippet of that file is shown below.
... # M1 homebrew first, then legacy homework PATH="/opt/homebrew/bin:/opt/local/bin:${PATH}" export PATH ...
Bring up a new Terminal window. Check the brew command is present in /opt/homebrew/bin.
(base) ~$ which brew
/opt/homebrew/bin/brew
(base) ~$
Next, install swi-prolog using the brew package manager.
$ brew install swi-prolog
Check to see if it's there.
(base) ~$ which swipl
/opt/homebrew/bin/swipl
(base) ~$
Finally, test swipl.
(base) ~$ swipl Welcome to SWI-Prolog (threaded, 64 bits, version 9.0.4) SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software. Please run ?- license. for legal details. For online help and background, visit https://www.swi-prolog.org For built-in help, use ?- help(Topic). or ?- apropos(Word). ?- ^D % halt (base) ~$Type Control-D to quit Prolog (^D). (Hold down CTRL and press D.)
We follow the instructions at https://www.swi-prolog.org/download/stable.
By default, swipl is NOT added to the PATH list
during installation.
However, we
should add it to permit swipl to be invoked directly from the command line.
In PowerShell, Get-Command allows us to check if
swipl is in PATH list. We
can then run swipl directly.
(Typing halt. will exit Prolog.)
In Windows Settings, we can manually add C:\Program
Files\swipl\bin to either the user or system Path if not added
initially during SWI-Prolog installation.
With the browser version, if you save the webpage as a .webarchive file, e.g. as
saved.webarchive, it can be trimmed down into a easily-viewable html
file using the shell script trim.sh.
The following screen
snapshot is from macOS Safari.
(Saving using format html directly in the browser does NOT save the
tree images.)
Then run the Perl script trim.sh in a Terminal window on the saved .webarchive file as follows:
./trim.sh filename.webarchive NAME
filename.html
where NAME is the name of the (collapsible) example section to be preserved
in the output.
Images are preserved and filename.html can be opened directly in any browser.