# (A ((Pretty OK) Lisp) Interpreter {in SETL})

This post overviews a Common Lisp interpreter written in the Set Theoretic programming language SETL. Source code is here: https://bitbucket.org/NeuralOutlet/setlisp
A complete list of available functions can be found in the doc folder.

SETL
Originally developed in  the 1960s by Jack Schwartz, SETL (Set Language) is peculiar in that it feels old and new at the same time. You’re writing imperatively with these chunky procedures then suddenly doing aggressive set comprehension like generating a set of unique primorial numbers in one terse but coherent line:

-- This is a comment
pset := {*/{p in {2..n} | forall m in {2..p - 1} | p mod m > 0} : n in {0..20}};
print(pset); --prints: {2 6 30 210 2310 30030 510510 9699690}


David Bacon developed the GNU SETL version between 1989-2009, fantastically nice to use, it is extended somewhat by adding POSIX support. Though it should be noted the parts that feel new were in SETL from its inception, it is said to be the first language to include list comprehension.

SETL spawned many versions of itself (SETLB, SETL2, ISETL, SetlX, etc) and influenced two other Set Theoretical languages called ProSet and Slim. Though out of all these languages the only ones still kicking around are GNU SETL, ISETL, and SetlX. There was a non-Set Theoretic language influenced by SETL – ABC (the predecessor to Python).

A good taste of the language can be found in the GNU SETL Om, for a more in depth understanding there is David Bacon’s PhD thesis. A ton of useful and interesting example programs can be found at Håkan Kjellerstrand’s SETL page. Historically there is also an early paper by Jack Schwartz.

SETLisp
So far setlisp has about 60 functions (SETLisp documentation) and the datatypes: Boolean, Number, String, Symbol, Function, List, and Set.

Sets – Lisp has a function for making lists, it looks like (list 5 4 3 3) which produces the list (5 4 3 3). Pretty simple, the function ‘set’ already exists for setting the value of a symbol so I chose to use ‘setl’ as the set function (setl 5 4 3 3) which yields {3 4 5}. The curly brackets indicate it is a set not a list. In Set Theory the order or duplicity of elements in a set do not matter so SETL orders the elements of a set by value and removes duplicates.

Expressions – The use of sets is extended to set-expressions, these are more of a playful idea than anything useful. The arguments are automatically bagged up into a set instead of being mapped to variable names in a list. Here you can see addition used as an s-expression and a set-expression:

The add function specifically is just the ‘+’ operator cast over a set or list of elements, which means that unlike ‘+’ in Lisp this one will do numeric affirmation aswell as addition. It infact extends further to also perform set union and string or tuple concatenation. I added the functions ‘append’ and ‘concatenate’ but they just call ‘+’. The code itself uses the ‘/’ notation alongside the list comprehension:

-- (+ args...)
return [+/sargs, env];
end proc;

-- {+ args...}
return [+/sargs, env];
end proc;


There is a ‘mapchoice’ function which is a play on the ‘mapcar’ function in Lisp and the Choice Function in Set Theory. The function ‘cardinality’ does the same as ‘length’. Also any s-expressions I add with only one or zero arguments is done for both s/set-expressions. {quit} is the same as (quit) for example.

This does open up overloading, a function can be defined as s-exp or set-exp or both (requires two identical definitions). The defun function works slightly different for each, s-exp are defined just as they should be, but the set-exp hides all parameters in a named set. This needs to be accessed with set functions such as from or with looping:

;; S-Expression
(defun my-func (param1 param2 param3)
(print param1)
(print param2)
(print param3))
(my-func 14 80 32) ; prints 14 80 32

;; SET-Expression
{defun my-func params
(print (from params))  ;Note: 'from' is destructive to the set, but
(print (from params))  ;      (loop for val in params do...) is not
(print (from params))}
{my-func 14 80 32}         ; prints 14 32 80


Behind the Scenes – SETL has another useful type (although it is more of a mechanism) called maps. Obviously straight from Set Theory – maps, sets, and tuple are the core of the language. A map is defined as a set containing only 2-tuples. Below is a map called stuff that has ‘this’ mapped to 5 and ‘that’ mapped to a tuple of the numbers 1 to 100:

stuff := {['this', 5], ['that', [1..100]]};
print( stuff('this') );
print( stuff('that') );


In SETLisp the variables environment is constructed with maps and so is the function type. To create local scope a list of maps is treated as a stack – checking from the top down searching for a value to map to a variable, then popping that definition map off the stack when leaving scope. The addition of an implicit map type in setlisp was my favourite feature to add, check out the Fun with Maps example.

Printing functions: write, print, princ, prin1, format.

Obviously the last one is setlisp specific, it is a wrapper for evaluating a SETL variable or variable construcor. In the setlisp.rc file you can see it is, in conjuction with ‘eval-setl’, used to allow SETL list/set comprehension in the macros ${ … } and$( … ).

Nil vs Om – These are two very similar concepts that appear in a lot of programming situations. In SETL any function without a return value will return om (printed as an asterisk ‘*’), this is the same for nil in Lisp. Lists in Lisp are constructed by cons cells ending with a nil cdr (a . (b . (c . nil))), in SETL a tuple is hypothetically of infinite size with om in every leading index [a b c * * … *]. One problem this brings up is that (list nil nil nil) should evaluate to (NIL NIL NIL) but [om, om, om] creates an empty tuple instead of [* * *]. The boolean types in Common Lisp are ‘t’ and ‘nil’ although anything not nil is considered true – SETL has the standard true/false duality but then om is there being all interesting.

Types – SETL doesn’t have characters, it’s very weird to me but a character is the same as a string of length 1. But what are strings made of? Aren’t they ordered sets of characters? I don’t know why there isn’t a byte-friendly char type in SETL but they exist in Common Lisp so I added a type system for various things. There are types for: Function, List, Set, Character, Complex, and Symbol. The syntax for characters are setup in the runtime configuration file, but I never implemented complex numbers in the form #C(1 2).

Macros – I didn’t add the more powerful ‘defmacro’ to SETLisp but for some of the beloved Lisp syntax such as ‘quote and #’function I added ‘set-macro-character‘ and ‘set-dispatch-macro-character‘. The extra syntax is implemented in the setlisp.rc file (read in before anything else). It begins with adding single line comments:

"Strings are nice, but let's make comments!"
(defun comment-macro (s c)
(values))
(set-macro-character ";" (function comment-macro))
(format t "  Comment macro added.~%")


and builds up to this definition for multi-line comments:

; Multi-line comments
(defun multi-line-macro (s c n)
(if (equal "#" (peek-char s))
(progn
(values))
(multi-line-macro s c n))
(multi-line-macro s c n)))
(set-dispatch-macro-character #\# #\| #'multi-line-macro)


# Mandelbrot: SETL & Lisp

SETL is a general-purpose programming language developed by Jack Schwartz back in the late 1960s. The language is multiparadigm – both Procedural (containing subroutines and control structures like if statements) and Set Theoretical. The latter is not often mentioned when talking about language paradigms – and is not to be confused with Logical Programming. The concept is outlined in the 1974 paper An Introduction to the Set Theoretical Language SETL. Importantly though data in SETL is of three main types: Atoms, Sets, and Sequences (also referred to as tuples or ordered sets).

A good overview of SETL can be found in the GNU SETL Om.

Pixels inside the Mandelbrot Set are marked in black, the code used to generate them (mandelbrot.setl) can be found here.

Generation of the Mandelbrot Set
On the Wikipedia page for the Mandelbrot Set you will find its formal definition, which looks like so: $M = \left\{c\in \mathbb C : \exists s\in \mathbb R, \forall n\in \mathbb N, |P_c^n(0)| \le s \right\}.$

The most fantastic thing about SETL is how powerful its Set Builder Notation is. Almost exactly as you would in the formal case (removing ‘there exists some real s’ for the practical application):

M := {c : c in image | forall num in {0..iterations} | cabs(pofc(c, num)) &lt;= 2};


For some reason SETL doesn’t support complex numbers, but they are easily handled by writing the necessary procedures we need like cabs, ctimes, and cplus dealing with tuples in the form [x, y]. The variable ‘image’ is a sequence of these tuples. Another procedure is written, pofc, which is a more practical version of $P_c^n(0)$.

Interaction with the Lisp graphical display
The goal of the SETL program is to produce a set of points that lie inside the Mandelbrot set. To actually display the image I used Common Lisp and displayed a widget with the image using CommonQt. In a very rudimentary way I had mandelbrot.setl take arguments about the image then print the set of pixel co-ordinates. All lisp had to do was swap and ‘{}’ or ‘[]’ for ‘()’ and read it as lisp code then update the image.

(setf in-set (read-from-string (parse-line (uiop:run-program "setl mandelbrot.setl -- -250 -250 250 8" :output :string))))
(draw-mandel instance in-set)


An after-thought was to make a Mandelbrot searcher where you could zoom and move using the mouse but the SETL code is such an inefficient way of doing it that it’s not worth it. As an attempt to mimic the formal definition it was highly successful and fun. Though much quicker SETL code could be written for generating the Mandelbrot Set.

Source file for mandelbrot.setl and the Lisp/CommonQt front end can be found here.

# MuSh: Multi-Shebang Scripting

MuSh is a super simple meta-scripting language for parsing multiple shebang statements that invoke different interpretors. Why would you want to do this? I have no idea. Although there is no real reason to do this you might want to just for the fun of it.

How it works
MuSh is python based and has a linear approach, it splits up the script into smaller single-language scripts then runs them one after the other. Variables are transported between scripts using a register file (msb_register.json) and hook-in functions which add code to the scripts for interacting with the register. There are two important syntaxes (syntaces?) for separating languages, the first is:

#!! <interpretor> <passed-variables …>

A little Guess my Number game that uses Shell, Python and Common Lisp. This example can be found at ‘examples/guess_my_num.msb‘ and uses the Vim syntax file found in the repo at editor_support/mush.vim.

Subscripting
The second separation syntax is for embedded use, it has open and close functionality:

#![ <interpretor> <passed-variables …>
#!] <passed-variables …>

MuSh uses the hook-in function inline_replace which replaces the embedded code with a call to a subscript (of that code). In the example below you can see how a python program might use subscripting to use Lisp. The left is the original, the right is after inline_replace has been called:

 def fact_lisp(n): #![ clisp n (defun fact (n) (if (< n 2) 1 (* n (fact(- n 1))))) (setf out (fact n)) #!] out return out  def fact_lisp(n): # Get 'n' from register ... from subprocess import call call("./subscript_0", shell=True) # Get 'out' from register ... return out 

The above code is from ‘examples/fact_speed_IO.msb from the repo. The meta-script starts with a python program that defines three factorial functions using subscripts to Python, Common Lisp, and Shell (sh). These three are called inside a python forloop 1000 times – calculating 10! each loop. Python timing methods are used giving:

 Subscripts Python Common Lisp Shell Time (seconds) 25.4605309963 18.8304021358 21.1056499481

It also defines a pure python factorial function, which it also loops for. Next the meta-script moves to a Lisp program which has a Lisp forloop and factorial function, timing here is done with (get-internal-real-time) and (internal-time-units-per-second). Finally the meta-script moves to Shell and runs a while loop for its factorial function. These script results seem peculiar to me, Lisp shows to be slower than Python and Shell is almost as bad as subscripting:

 Scripts Python Common Lisp Shell Time (seconds) 0.002014 0.009645 14

I find it strange that when using a python loop/timing – python was the slowest, but when using native loops/timing – python was the fastest. This could be because my implementation is incorrect somewhere or python just has great looping but bad recursive arithmetic. Maybe it’s a reflection of how python interacts with the register. I’m more confused by why shell is so slow.

# AI: Conway Creatures!

Recently I’ve been reading up on Cellular Evolutionary Algorithms and on the use of Genetic Algorithms (GAs) to evolve Cellular Automata (CA). I want to try out all sorts of different things so I will be doing a series of posts where I explore different interpretations of a concept – Conway Creatures.

Get Involved!
I have a few programmers, logicians and AI enthusiasts that follow my blog so I wanted to see if I could make something of the concept. I’d like to see all your interpretations of what a Conway creature is. Given a rough description, which is essentially: creatures (2D,3D, etc) of which the properties are evolved in some way using a mix of CA and GAs. If I get any i’ll do posts dedicated to the entries. I would also like to see varied definitions of the concept such as the use of other works by John Conway (e.g., the growth rate of the Look and Say sequence – Conway’s Constant, the Surreal Numbers, Conway notation for polyhedra, etc), other CA rules and other Evolutionary methods.

The First Detour – Longevity in Game of Life:
I began to write the program and found myself wondering “What are the characteristics of longevity in CAs?” and I’m still not sure. I’ve been trying different takes on mutation and crossover where I take chunks of the board and flip them or turn them all on/off. It doesn’t seem to make much difference, I was hoping it would conserve locality. I also tried out Boltzmann selection (Simulated Annealing) but tournament selection (dueling) worked much better. Any ideas?

This is my program so far, I am taking a little detour to look into longevity, but in Issue 1 there will be a creature where the 3D terrain is. Probably not very complicated, I was thinking of making the creature some sort of shape, like an octahedron.