---
layout: ../Site.layout.js
---
# Lisp's prog feature - tagbody-go and my antifunctional game devlog tootcoding exploration

In openbsd C style, `GOTO` is used because it is transparent. How does this clean up? Well it does GOTO cleanup - you scroll to `cleanup:`, and that is what is going to happen in imperative code. Switching back to lisp, the `with-` macros which imply a cleanup happens have good cause. If you see a macro named `with-foo`, you know in your lisp heart that something like this has been done:

```
(defmacro with-foo
    ((&rest foo-args)
     &body body)
  `(let ((foo nil))
     (unwind-protect
	  (progn
	      (setq foo (create-foo ,@foo-args))
	      (progn ,@body))
       (when foo
	 (cleans-up foo)))))
```

In lisp, the [`unwind-protect`](https://www.lispworks.com/documentation/HyperSpec/Body/s_unwind.htm) special form guarantees that the second form happens/cannot be avoided (it pre-allocates it or something).

Now that we all know how important `unwind-protect` is, let us [start to roll Dijkstra in his grave](https://dl.acm.org/doi/pdf/10.1145/362929.362947).

# `#tootCoding` on the Mastodon

I am exploring presenting my game jam as reuseable shared fediverse social media infrastructure.

In practice this has meant that each step I am writing some toots containing code, then my game implementation is some data, followed by an elisp-link to an eev anchor in that toot. Some code will be worth a thousand words:

## Toot for associating an image with a game symbol

(literally, [this toot](https://gamerplus.org/@screwlisp/115483514644964652) from [my second devlog](/lispgames/the-other-threeish-checkmarks/))


> #tootCoding (read my jam articles about the experiment) #commonLisp #NicCLIM 
> 
> ;; ยซ๐ŸŽญยป (to โ€œ.๐ŸŽญโ€)
> 
> (setf (get ** :bitmap) *)
> 
> i.e. it sets the :bitmap property of the second-last arguement to the last arguement.

after which giving my owngame's symbols pictoral representations instead of printing in the game is like this:

```
'SOLID
'IMGS/SOLID.PNG
;; (to "๐ŸŽญ")
'ROCK
'IMGS/ROCK.PNG
;; (to "๐ŸŽญ")
```

Kind of forth-style game-specific-knowledge entry. To make explicit what is implicitly happening here

## The buttons I press

1. `'SOLID`
1. + I press `F8` (pitch line to my lisp repl).
1. `'IMGS/SOLID.PNG`
1. + I press `F8` (pitch line to my lisp repl).
1. `;; (to "๐ŸŽญ")`
1. + I press `M-e` i.e. evaluate elisp. This jumps me/my cursor to my eev anchor, `;; ยซ๐ŸŽญยป (to โ€œ.๐ŸŽญโ€)`. Hence
1. `(setf (get ** :bitmap) *)`
1. + I press `F8` to pitch this line to my lisp repl as well. `*` and `**` are special lisp repl variables containing the last and 2nd-last repl results.

Admittedly, I currently do not have a favourite way *to get back to where I was* after following the anchor. There *are* lots of ways but I have not picked a best one for this interactive use. Anyway, most of my game dev is entering knowledge describing my particular game using generic GOTO-like infrastructure.

In practice I am tapping these keys interactively:

- `<F8>` = give line to lisp repl
- `M-e` = do elisp to follow eev link
- `C-n` = next line (line was informational, or I do not want it here)

[eev](https://anggtwu.net/#eev) supports using red star / bullet lines for using `<F8>` for elisp as well, but `M-e` lets you evaluate nested elisp expressions in the middle of a line, so.

```
โ€ข (to "๐ŸŽญ")
```

# But what is the "lisp program" of these interactions?

Here is the lisp code I came up with that closely tracks my interactive useage. I wrote this to try and understand the dynamic; forgive me if something is already obvious to you.

## Basic `prog` premise

```
(prog
    ((goer (lambda ())))
 start
   (print 'hej)
   (funcall goer)
 start-done
   (print 'ho)
   (setq goer (lambda () (go end)))
   (go start)
 end)
```

as we can see this `print`s `HEJ`, then `HO`, sets `goer` to `(lambda () (go end))`, goes back to the start, `HEJ`, but then it calls the lambda and goes to the end so there is no infinite loop.

This seems like enough to explicitly duplicate my interactive flow as a lisp `prog`ram.

# My lispgamejam gamedev so far as one lisp `prog`

I introduced `starset` to simulate the repl special `*` variables. Technically I should have `-`, `/`, `+` as well. Also for *slime* to treat `ยง` as a tag, I had to prefix it with an underscore or something.

NOTE: I since dropped the cute unicode/latin1 for lisp-style symbol names as tags since memorizing these arcane sigils is like trying to use APL.

The key point here is that this `prog` represents operating more or less *exactly like I do interactively* and I am curious to know what that looks like.

```
(macrolet
    ((starset ((form))
       "starset ((form)) simulates lisp repl's * ** *** vars"
       `(psetq * ,form ** * *** **))
     (bounce ((tag1) (tag2))
       "bounce ((tag1) (tag2)) achieves (go tag1)..(go tag2)"
       `(progn (setq resumer (lambda () (go ,tag2)))
	       (go ,tag1))))
  (prog
      ((resumer (lambda () (go devlog-0)))
       * ** ***)
   resume
     (funcall resumer)
     
   devlog-0-tags
   make-map
     (starset
      (apply 'rect-file
	     ***
	     (append ** (list *))))
     (go resume)
   gui-edit-map
     (starset (enclose-map *))
     (go resume)
   clobber-abc-y1y2x1x2
     (starset (append ** *))
     (starset (apply 'clobber-rect *))
     (go resume)
     
   devlog-0
     ;; Making maps
     (starset ('grass-clearing.map))
     (starset ('(12 8)))
     (starset ('(grass)))
     (bounce (make-map) (grass-mapped))
   grass-mapped
     (starset ('grass-clearing.map))
     (bounce (gui-edit-map) (viewed-grass-map))
   viewed-grass-map
     (starset ('solid-rock.map))
     (starset ('(12 8)))
     (starset ('(solid rock)))
     (bounce (make-map) (solid-rock-mapped))
   solid-rock-mapped
     (starset ('solid-rock.map))
     (bounce (gui-edit-map) (viewed-solid-rock-map))
   viewed-solid-rock-map
     (starset ('rock-cavern.map))
     (starset ('(12 8)))
     (starset ('(rock cavern)))
     (bounce (gui-edit-map) (viewed-rock-cavern-map))
   viewed-rock-cavern-map
     (starset ('(solid-rock.map rock-cavern.map mountain-cave.map)))
     (starset ('(1 3 2 4))) ; argh y1 y2 x1 x2
     (bounce (clobber-abc-y1y2x1x2) (composed-mountain-cave))
   composed-mountain-cave
     (starset ('mountain-cave.map))
     (bounce (gui-edit-map) (viewed-mountain-cave-map))

   devlog-1-tags
   assign-bitmap
     (starset ((setf (get ** :bitmap) *)))
     (go resume)
   create-door
     `(lambda
	  (&rest r)
	(execute-frame-command
	 *application-frame*
	 '(com-change-map ,*)))
     (go resume)
     
   devlog-1
     (starset ('SOLID))
     (starset ('IMGS/SOLID.PNG))
     (bounce (assign-bitmap) (bitmapped-solid))
   bitmapped-solid
     (starset ('ROCK))
     (starset ('IMGS/ROCK.PNG))
     (bounce (assign-bitmap) (bitmapped-rock))
   bitmapped-rock
     (starset ('TREE))
     (starset ('IMGS/TREE.PNG))
     (bounce (assign-bitmap) (bitmapped-tree))
   bitmapped-tree
     (starset ('GRASS))
     (starset ('IMGS/GRASS.PNG))
     (bounce (assign-bitmap) (bitmapped-grass))
   bitmapped-grass
     (starset ('LAMBDA))
     (starset ('IMGS/LAMBDA.PNG))
     (bounce (assign-bitmap) (bitmapped-lambda))
   bitmapped-lambda
     (starset ('rock-cavern.map))
     (bounce (gui-edit-map) (viewed-rocky-cavern))
   viewed-rocky-cavern
     (starset ('grass-clearing.map))
     (bounce (create-door) (created-grass-door))
   created-grass-door
   end))
```

I have a few thoughts!

## This is a less sophisticated version of [interlisp medley](https://interlisp.org/software/using-medley/#getting-started)'s USE x FOR y IN lines

Whereas each executive in [an interlisp medley lispm](https://online.interlisp.org/user/login) has conversational lisp (*negotiating with this executive* rather than requesting the executive perform a lisp action) history features such as `REDO` and `USE` for out-of-order-redoing previous lines, possibly with symbolic substitutions (`USE`), my ANSI CL mechanism must use a `tagbody` (in my case, `prog`'s implicit `tagbody`).

Further I needed to place a new tag immediately after my `bounce` macro which stores a `tagbody-go` in a lambda, and the redoable tags conclude by funcalling the stored lambda.

Furthermore, and annoyingly I have to witchcraft in the `* ** ***` repl special (my fake ones are lexical, I guess) variables. I chose to write both `starset` and `bounce` macrolets to strongly imply what they are doing every moment. This was annoying to type (I say type but I used an emacs keyboard macro and pressed `e` a lot).

On the other hand, in emacs slime, it seems straightforward to programmatically process the elisp strings file of inputs-received-by-a-slime-repl exposed by e.g. `slime-repl-save-history` (I do not know where the documentation lives in [slime's documentation](https://slime.common-lisp.dev/doc/html/index.html#SEC_Contents)). Either slime or ANSI common lisp's [READTABLE](https://www.lispworks.com/documentation/HyperSpec/Body/t_rdtabl.htm) could automate generating my `prog` here for a lisp image as it happens. Since it is easily automatable, I am somewhat happy with the more-transparent-with-what-is-happening form I wrote.

Having observed it is possible to do, it is deeply unhygeinic. Basically we issue a GOTO and hope that the place we went to eventually cedes control back to a second GOTO we set a local variable to. The lexical environment of the tagbody being modified is the same one we also were in and stay in.

## `prog` tags are basically programmatic markdown headings

I am tempted to say that the tagbody tags make a `prog`=repl-history almost directly useable as my blog's article format which would be pretty cool. I seem to remember https://mdhughes.tech describing REPL-driven programming as being the exact opposite of literate programming. I would like it if my repl useage reasonably was the literacy.

Flatness and lack of hygeine in the `tagbody` environment could be abrogated by closure-driven functional programming, also popular in interactive REPL useage.

## Redundancy with `defun` versus local transparency

Admittedly, I feel like I  am jumping through a lot of hoops to use two gotos instead of just using special scope `defun`s on the justification that fairly pure `tagbody-go`s are more transparently and locally traversable than functions accrued from different packages. Both seem to be points - it is abstruse not to use `defun` when you basically want `defun`, and `defun`s and `closure`s are inspectable via `function-lambda-expression` after all - on the other hand, a single goto-based openbsd-style-`main()` single `prog` is directly followable and unmysterious.

## Clear meaning of what programming-the-game *meant* in one case

While their is no enduring, perfect formula of what making-a-good-game means moment to moment, here we can see that the day I wrote [my 0th devlog](https://screwlisp.small-web.org/lispgames/actual-game-gamejam/), I wrote what is at `devlog-0`, the day I wrote my [1th devlog](https://screwlisp.small-web.org/lispgames/the-other-threeish-checkmarks/), I wrote what is at `devlog-1`; and I jammed these hot into a repl and file source is a post-ex-facto processing of that repl experience's easily available history.

This lets me inspect and aggregate what my first person experience of [lispgamejam](https://itch.io/jam/autumn-lisp-game-jam-2025/topic/5489995/who-is-doing-common-lisp-and-how) was devlog to devlog, jam to jam (my repl's first person experiences anyway).

It seems like

## Not having dependencies is important

to this transparency and direct scrutibility of the openbsd-`main()` style lisp `prog` implicit `tagbody`, and maybe as a general principle. Let us review my nascent game's dependencies.

### [Embeddable common lisp](https://ecl.common-lisp.dev/) = purports to conform to ANSI common lisp

Compiler to the popular and perhaps uniquely reliably static modern language standard, ANSI CL. Some allowed extensions (multiprocessing, utf8, compiler particulars, the MOP, weak hashtables etc) generally being direct yet also historical support for the small number of canonical additional de facto standards. To first order it is just a conformant ANSI common lisp implementation directly comparable to other conformant ANSI common lisp implementations.

So dependency one - conformant ANSI CL compiler with allowed extensions.

### [McCLIM](https://codeberg.org/McCLIM/McCLIM) = a [common lisp interface manager 2 spec](http://bauhh.dyndns.org:8000/clim-spec/index.html) implementation

While it is a spec and not a standard, this spec is currently implemented at least by [McCLIM](https://mcclim.common-lisp.dev/), [Lispworks](https://www.lispworks.com/documentation/lw80/clim/clim.htm) and [Franz Inc](https://franz.com/support/documentation/contents.html#clim-ug), historically by Symbolics and seems to have become eternal. I note that [Symbolics' great manual](http://lispm.de/docs/Publications/UI/1994%20Symbolics%20CLIM%202.0.pdf) starts with a note about integrating opengl and their CLIM 2 spec implementation. McCLIM has extensions and demos, also I guess it is worth noting that CLIM 2 implementation is defined in terms of implementing the CLIM middleware out of whatever available nonportable environmental tools, and hence having ported your CLIM implementation which sits atop that middleware to a new environment.

### [My own NicCLIM map editor](https://lispy-gopher-show.itch.io/nicclim)

This is the only fluffy, non-spec/standard item being my own contribution of the last few months. In my heart of hearts' highest aspirations it is my exploration in search for something like VI in a universe where [ANSI CL](https://nhplace.com/kent/Papers/cl-untold-story.html) and [ex(1)](https://man.openbsd.org/OpenBSD-5.7/ex.1) have been confused (very confused) made using McCLIM instead of curses. At some point, if I am programming I must also contribute something. For the jam I guess I am exploring *using my NicCLIM as intended* to create and edit map files, where the NicCLIM map files as such are a game and might be independently deployable as a game.

NicCLIM itself is pretty close to being a thin wrapper on top of using-CLIM-spec-[commands](https://www.lispworks.com/documentation/lw80/clim/clim-ch9-8.htm#CLIM)-execute-frame-command-and-[tabling-macro](https://www.lispworks.com/documentation/lwu41/climuser/GUID_281.HTM#HEADING281-0)-like-the-oft-reproduced-tutorials and just reads and writes files of ANSI CL s-expressions with [`prin1`](https://www.lispworks.com/documentation/HyperSpec/Body/f_wr_pr.htm) and [`read-delimited-list`](http://www.lispworks.com/reference/HyperSpec/Body/f_rd_del.htm).

### Not dragging in anything else

Almost everything I am touching is formally specified. The thing that is not formally specified or standardised is my interpretations of VI's the-rogue-keys (er, adapted to hextille), two cursors, `clim:command` ~VI macros, and instead of host shell calls it makes host lisp calls.

My game creation then, is basically feeding knowledge into well-knowns. Adding/calling a command? It is the CLIM 2 thing. A map cell contains a lambda? The ANSI CL thing. Displayed in a table? `clim:formatting-table`. The word `lambda` renders as a beautiful green lisp alien looming behind the lambda-list and body? The `clim` thing (+ bitmap cached in an ANSI CL hash-table).

The idea that one can `pip install` or `npm something` and copy gigantic source unknowns into what then is no longer *your own code* is a disaster. The implementor of your CLIM 2 spec implementation has taken the burden of every upstream dependency's weight onto their own shoulders; Atlas holding up the sky so that we do not need to know anything but the CLIM 2 spec (and lisp purporting to conform to the ANSI CL standard similarly) with a handful of implementation notes. Aside: for me, [both of these are one specific person](https://functional.cafe/@jackdaniel) (and all the contributors, I guess).

# Aside from that repl history as a `prog` form earlier, what *is* a game?

In terms of NicCLIM, a game is a collection of presumably connected map s-expression files generatable and manipulable via NicCLIM.

So to make a game I can (in no particular order despite the numbers)

1. Make some maps. Each cell of the map is a list of symbols and lists. The symbols and dimensions of a map are a thing you make with NicCLIM.
1. Specify any non-textual depictions of stacks of map symbols like the pictures in my 1th game jam devlog.
1. Add whatever your game's e.g. movement mechanic is as a CLIM command (using the easy way).
1. Movement/game-command-triggered game mechanics are either host lisp `lambda`s or macros (in the VI sense) of `NicCLIM`'s and your own `clim` commands (if you move here, trigger moving that symbol there at 2 moves/second)
1. All the technical stuff is done and there is nothing but authoring the game's story and other art.

# Conclusions

This article got kind of weird ([other peoples' code is the work of the devil!](https://appdot.net/@mdhughes/104489984708298096)!) as the day drew on.

I implemented a lisp REPL history multiline goto-based redo as an ANSI CL implicit `tagbody`. Then I suggested that for code you include that you did not personally author, you are still responsible for that code despite not being its author and hence suggest only dragging in to-first-order-immutable standards/specs being ANSI CL and the CLIM 2 spec (assuming that an implementation purporting to conform does so: if it turns out not to for your purposes, another implementation of the same standard/spec would be switched to).

My NicCLIM commands are in alpha and hence the-NicCLIM-commands are the-NicCLIM-commands. After revising them based on available experience and commentary, I will specify them as formally as I can concommitantly to the NicCLIM beta.

Lastly, I proposed five game activities for a NicCLIM-maps-as-a-game:

- making maps being hextille layouts of lists of symbols and lists
- add (and make!) any non-`symbol-name` art to those symbols (like my devlog 1 bitmaps but do a better job)
- add your game's own `clim:define-command`s in the usual `clim` easy way.
- add ANSI CL `lambda`s or *macro*s `clim`/`NicCLIM` command sequences triggered by your game's commands
- Everything else is just your game's story ando ther art.

Where my first two lispgamejam devlogs attempted the first two.

This article basically just viewed my NicCLIM useage this game as a flat list of lisp REPL interactions rather than as a social tree of fediverse toots, though it is interesting to see the same thing from different vantages sometimes.

# Fin.

Talk [on the Mastodon as always please](https://gamerplus.org/@screwlisp/115489700650702280). The first-four-jam-days-retrospective nature of this article makes it suitable for weighing in with your opinion, surely! Also remember this week's Tuesday-night-in-the-Americas show with gopher://gopher.someodd.zip (https://someodd.zip) is less than 24 hours away, [same time as always](https://gamerplus.org/@screwlisp/115454439591187698) (for years). There will be a new unix_surrealism banner this week!