Welcome everyone to my EmacsConf presentation,
where we're going to look at Lisp's vdemo[??] app from 1978,
but done in modern Elisp.
Then we're going to look at getting inferior-lisp working,
my dear Common Lisp.
Then we're going to use the Common Lisp interface manager,
the open source child of the Common Lisp interface manager,
McCLIM, from inferior-lisp in Superior Lisp,
which is the opposite order that I initially thought
we were going to do things in,
but this is how it's kind of turned out.
So it's this article,
I thought, from 1978, was interesting to us today.
“Programming in an Interactive Environment:
the ‘Lisp’ Experience.”
Explaining what all these LISP programmers were doing to
people unfamiliar with LISP programming.
“LISP systems have been used for
highly interactive programming for more than a decade.”
This was from 1978.
And we're just going to go and,
almost verbatim, port the demo application for LISP
out of 1978 Interlisp and into Emacs Lisp.
And we're going to do it without Org Mode,
because I think everyone is finding out
how great Org Mode is already.
For inferior Lisp, I thought instead of org-mode,
we'll theme it around slime-mode and then it turned out
most of this presentation happens in Emacs Lisp,
because this is an Emacs Lisp conference.
But I found out that there's ielm-mode,
which is pretty similar to slime-mode,
but in our hearts, we can imagine that this is
an Emacs example, homed around slime-mode,
Superior Lisp Interaction Mode for Emacs, instead of org-mode.
Though, you know, I do secretly use org-mode as well,
not very secretly.
But that means we're kind of improvising,
improvising a presentation mode.
So we have this big buffer of Elisp, and let's just...
This is me, not Sandewall, out of interest,
let's make a keyboard macro,
go get the S-expression wherever the cursor is,
move it to the next S-expression, paste it in here,
and the keyboard macro, alright.
What was basically happening...
So the demo application in this case is
a scheduling application.
And so you can imagine improvising a calendar like this
if you weren't existingly using an
org-mode integrated calendar.
So, you know, just have a list and maybe
each list is of sublists, where the first element,
the car of the sublist, I guess,
is a sensible-sounding date format, like sat dec 7,
this is clearly the first day of EmacsConf.
Then after that, a list of basically from and to times,
and then a quick written description of whatever event
was at that time.
So similar to what we were seeing recently
as of me recording this in our Structure and
Interpretation of Computer Programs study group,
you have all these little methods, sorry, defuns.
So hours of a time is actually just car of the time,
minutes of the time, cadr of time.
And so we all know these kind of little,
basically turning car and cadr,
which we do use into descriptive names like from and to.
You can see how this lines up with the appointments.
So for "reproducibly building emacs" described event,
I guess from would be 16 25.
Let's just grab that and literally use those,
because we're in interactive programming, right?
So we have this quoted form and then
let's do from of that. Great.
And let's do minutes.
So from 16 25, 16 45 reproducibly building Emacs,
so when I do from to that I get 16 25
when I do minutes to 16 25, I get 25
and a description of this number in octal and hexadecimal,
out of interest.
What was up next? Okay, getting nextday from a date.
And so, what was it? Saturday, December 27th.
So what happens? So this function,
I guess this was part of Sandewall's personal exploration of
atoms using symbols with property lists,
with an attached property list to every symbol.
And so you can kind of see how this works.
I get whatever was keyed by the symbol nextweekday out of
the day symbol, so I guess we would do...
so if we had Sat December 6, I guess we get Sat
Oh, it destructures that itself somehow, get nextweekday.
Sorry, nextday.
set December 6th
But of course these weren't defined yet,
so what if we (setf (get 'sat 'nextweekday) 'sun)
and it's going to be sun right
And then if we (nextday '(sat dec 6)),
Sunday, December 7th.
Yeah, so that kind of makes sense in an intuitive way.
And you can see cond is being used.
So if you're not a Lisp person, cond evaluates a condition.
If the condition returns non-nil,
it executes the code attached to that condition.
It evaluates each of these conditions in terms
and then stops when one returns non-nil,
as you might expect as a Lisp programmer.
Let's keep marching along.
Okay, so we have to populate this.
And this was an interesting one.
As you can see, this was my attempt.
let days mon tue wed, so forth.
Then I used cl-loop from Emacs Lisp, you know,
for day in days, for nex in cdr days, setf nextweekday.
This I thought was surprisingly deep, was that
Lisp programmers, Sandewall thought,
are basically constantly trying to break new ground and they
lose interest very quickly when
that's not what they're doing.
And he was making the point that breaking new ground
involves solving a problem exactly once.
And so you kind of should do it
in the most expedient way possible
to solve it kind of for the first time.
And after that, it's not breaking new ground anymore.
And so I thought that was a kind of fun point
from Sandewall's paper that we could kind of chew on.
Do something similar for months and month lengths.
But as we can see, if I get Feb,
nrdr days I think that characters in 1978,
characters and symbols in 1978 were more precious
which is why Sandewall was writing in this abbreviated way.
We might write more verbosely these days.
We get 28th but it is in fact a leap year,
so let's just set that to be 29. Now, it's fine.
Then I guess if we do, we were doing nextday.
Sure, nextday. I don't know what day it was.
let's assume it was Sunday Feb 28
some kind of typo crept in there, but we can deal with it.
Let's just setf get sun nextweekday month.
So once we've solved it once, we should be fine, right?
Okay, I think I have to speed up a bit.
Yeah, there we go, Monday February 29th and then
what if we nextday... Tuesday March 1st.
Okay, it basically seems to be working.
And I'd argue it's actually fun that
we kind of had to do that.
Then, just imagining you're kind of functioning with
other people: day begins at 900, ends at 1700,
so kind of a 9:00 to 5:00, imagining... though perhaps,
shorter is more appropriate,
but let's not quibble about that.
What was happening next in this app?
holesin. Oh, yeah, so get me the free slots
in from start time, list of appointments,
remembering characters, I guess, were more precious
is my theory.
And then an end time, so if I go holesin and then from 900
to where I've written 9 space 0 0
and what are my appointments?
So I have a list of appointments that
need to have start times and finish times.
So let's go 12 59 to 13 01.
The description, I guess, can be test.
And then let's finish that at 1700,
like we kind of thought.
Oops, some of these were meant to be arguments.
Okay, there we go.
And so the available times between nine and five,
if there's one appointment from 12:59 to 1:01,
are from 9 to 1259 and from 1 past 1 to 5,
which is kind of what we were expecting.
And so our appointment app is kind of coming along.
Then we have commonholes,
kind of works in a sensible way.
Do we have, what are some common holes from
two lists of appointments, I guess? commonholes.
I guess, let's have one person have an appointment
from 9 to 10.
That's going to be their only appointment.
And let's have another person have an appointment
from 9.30 to 10.30.
Oh, we didn't do beforetime yet.
This is the order Sandewall implemented things in there.
Ok, there.
So the commonholes are from 9.30 to 10.
That's actually the overlapping time.
I'll re-record this
if some kind of gremlin has crept into my things.
And then, what did we first start by doing?
Emacsconf track 1 and Emacsconf track 2,
and we'll do it on Saturday, December 7.
commontime, and I'm being prompted, of course.
emacsconf-track-1,
emacsconf-track-2,
the date that we grabbed.
Let's say we want five minutes.
And, as always, I'm forgetting to quote things.
And so my opportunities for common times
between emacsconf-track-1 to emacsconf-track-2
on the first day of the conference,
Saturday, December 7th, for five minutes.
I have an opportunity between 9:20 and 9:40,
11:40 and 13:00, 13:10, 13:25,
13:45, 13:55, and 16:15 to 16:25.
So I think that's all working.
And it was done with almost exactly the same code,
except for my loopy populating symbol plist bits earlier,
in Interlisp in 1978 as Emacs Lisp in 2024.
I thought that was pretty interesting that
you could do that.
I think setf get was put prop
was the biggest difference in 1978 Interlisp and
modern Emacs Lisp.
And obviously modern Emacs Lisp has Common Lisp loop in it,
kind of. It's another big difference.
How are we doing for time? 17 minutes?
Great, because now let's get a bit closer to what
my talk title has promised.
We're going to use Common Lisp from Emacs Lisp
and we're going to use Common Lisp Interface Manager,
the open source implementation of
Common Lisp Interface Manager from
Inferior Lisp from Emacs Lisp.
And what we just went over in Sandewall's paper...
This was the starting point, and Sandewall says,
well, if you just kind of jammed these ideas using lists
you just kind of made hour a synonym for car and
minute a synonym for cadr and so forth,
you can then make a whole bunch of improvements.
Can we actually get a glimpse of the …
No, I didn't really write this.
Yeah, so you can see I basically just ported out of
the Interlisp code in the text of this paper.
Yeah, you see from lambda of appointment,
car appointment, and that's defineq.
I guess Interlisp in 1978 used defineq,
whereas we used defun in Elisp,
but I'd encourage you to explore that yourselves.
But the extension that I wanted to develop today is,
since Common Lisp interface manager is just Lisp,
and Inferior Lisp is just Lisp,
and Emacs Lisp is just Lisp,
and Interlisp in 1978 is just Lisp,
we could kind of use them all together
in a kind of funky way.
But a complaint you often hear, or a statement of confusion
that you often hear as a Lisp person,
people from other languages often can't kind of figure out
how to get started with Lisp.
So I'm just going to try and do everything here and now.
And this is the second piece of my three pieces,
so let's just get inferior lisp and McCLIM happening.
We normally use slime Superior Lisp Interaction Mode
for Emacs, which we could get from Emacs's package manager.
If I go package-list-packages and then we wait
for however fast my network is,
we're going to see how long it's been
since I updated something.
Yeah, but you see it's in MELPA, right?
It's got to be somewhere here.
Yeah, all right.
So there's one slime available in non-GNU,
one possibly more recent one available in
the MELPA package repositories.
I don't know about you,
but I can sympathize with people who feel confused by this
because I think if you look online,
if you found a search engine result,
it doesn't customize these like I customize them.
So let's just do this.
customize-variable.
package-archives.
Yeah and you can see here I've ins-ed gnu, non-gnu, and melpa.
It's melpa, not melpa stable.
Saved and set.
So that's how I do that.
We're just kind of totally get an inferior lisp working.
And then, like we saw before,
this might occur, buffer is still open.
No. occur. slime.
So we could install and execute that.
I cloned slime since Common Lisp people
might use slime and swank, like McCLIM does outside of Emacs.
I think we can secretly see
I've got it here already in my ~/.emacs.d/slime,
but you could install it like that. The hotkey is I,
and then execute the install.
I realize you all already know this,
but many of you might not yet be Common Lisp programmers,
and you can use both Superior and Inferior Lisp.
Instead of package archives in Emacs,
in Inferior Lisp, and with great controversy,
we often use QuickLisp.
People sometimes complain QuickLisp releases
get out of date quite quickly.
But there was one recently, so they're pretty in date.
And so there should be a …
Yeah, so basically you download quicklisp.lisp,
you check its SHA-256 sum.
So I guess in, ooh, over here, if I press D,
~screwtape/downloads/quicklisp.lisp.
Great. If we open a shell, we realize that
this is just riveting for all of our experts there.
sha256 ~/Downloads/quicklisp.lisp
Your SHA-256 might be different to mine.
Somebody please tell me during the actual conference,
the right Emacs idiom to do this.
I guess it will be tools decrypt something.
But then once you have QuickLisp,
let's go back to our shell.
I'm on OpenBSD or a BSD, so I type pkg_add ecl
to get embeddable Common Lisp.
However, I think I already have it.
And then, let's start ecl [embeddable Common Lisp].
Quicklisp inserts itself already,
but just loading that quicklisp.lisp file
kind of would get you here anyway.
Now let's (ql:quickload :mcclim)
I'm actually following my plan.
McCLIM is kind of like Emacs in that
it handles all sorts of graphical stuff
like if you have GTK Emacs,
you know, it can do really a lot of stuff.
That's the reason why compiling and loading
the McCLIM package takes a while
and I do use my old computer laptop,
my old computer challenge laptop all the time,
so when you do this, your computer will be
substantially faster or you will be feeling
smug about how slow you're running your computer,
and so there's no problem.
Next, we're going to start Swank
which is the Lisp part of Emacs's slime-mode.
If I remember, we looked at this before
in my .emacs.d,
and then there should be slime/start-swank.lisp.
Let's just grab that and load it.
You don't have to type #p.
The string will work as well as the path name,
but it's kind of fun to do so.
Now, slime-connect.
You installed slime earlier.
Default values.
Oh, the reason we had to do this
and not use Slime, start Slime normally was that
CLIM, Common Lisp Interface Manager,
McCLIM, implementation of the
Common Lisp Interface Manager spec, also uses Swank
and McCLIM really wants to be in the driver's seat.
We can have our Emacs connect
to the Swank that McCLIM was already running.
So (in-package :clim-user)...
I don't know if this is an Emacs Lisp idiom,
so you normally have user packages to absorb user code
just for fooling around.
Then let's just use clim at all.
And so clim does lots of things around presentations
but one thing it does is automatically, to a large extent,
generate graphical user interfaces.
So there's a lot to it that's not about graphics,
kind of richer interfaces than
ANSI Common Lisp's character streams.
But let's use it to grab a graphical pop-up
that returns a value.
So we have this accepting-values tool.
t is just choose whatever you think the default stream is.
We're going to want our own window, t as well,
so just a keyword argument.
After that, we can just write things like (accept 'string).
And I'm just doing this in, for people only listening,
I've just done this in my ECL Slime REPL.
Enter a string: foo bar baz.
Alt-Enter, I think, is the shortcut to return that.
As you can see, its first return was "foo bar baz",
and it had second and third returns,
string being the type, presentation type that it got,
and t, I think, to indicate that it exited successfully.
We can also do expression, might be more interesting.
There are a whole bunch of these.
clim's examples folder is pretty good.
And the documentation, everybody's documentation,
McCLIM's documentation, you know,
lispworks and franz's documentation will tell you about
the different default presentation types you can accept.
And they're pretty intuitive and
they're kind of very Lisp compatible,
which everything kind of is.
We could accept an expression. foo bar baz.
return "foo bar baz 123" because that's what I wrote.
And now the kind of pièce de résistance
of putting those things together.
Let's just run over to our scratch buffer.
Oh, or our ielm thing, right?
That's what we're actually doing.
So now, I think we're going to do, hang on,
M-:.
I think it's going to be slime-eval-save,
because it'll eval asynchronously.
There's a question of how to get the value out of
the asynchronous slime evaluation.
And so an obvious way is to yank it.
I'm looking forward to learning from kickingvegas.
He finally makes it stick in my brain how to...
Options other than just starting to write a command
in the minibuffer and then mashing Tab
and looking at what the likely sounding results are.
That's what I will be learning this conference, if anything.
slime-eval-save and then, what was happening over here?
(accepting-values (t :own-window t) (accept 'expression)).
Kind of confusingly, slime-eval-save takes a string,
but it works really well, I'd argue.
I think it's about to work really well.
Ok, this is great.
So you can see I've used... Oh, please enter an expression.
So we're doing an expression.
And so let's write like (3 4/2 5/6).
That's an expression, right?
And now I've yanked it.
I should have really been in *scratch*,
because I just want to dump. Sorry, *scratch*.
Dump whatever that did.
Oh, yeah, and see, it kind of simplified that
while it was reading it.
So running in Elisp, (slime-eval-save "(accepting-values
(t :own-window t), accept 'expression))").
And I got the three returns all the way
from McCLIM to inferior-lisp to Elisp.
3, 2, 5/6.
Second return, it was a presentation type of expression,
returned successfully, key.
Yeah, so that's pretty cool. How out of time are we?
Oh, we did this in basically half an hour.
Maybe we could stop and assume there will be a bit under
half an hour of interactive discussion.
And when I also watch this and also receive suggestions,
there will be additions and changes to make, I think.
But can we quickly defun accept-date?
Let's not take any arguments.
Let's do this.
accept-date.
Saturday, December 7th.
Oh, it doesn't return it.
But it gets pretty close to returning it.
I guess it yanks it.
I would have to call … I'm going to say it's slime-sync,
at which point it will resolve the slime-eval-async.
And then I could get the first value out of
my kill-ring pop, right?
Does kill ring pop what I want?
You know, you tell me in the interactive feedback,
which should be happening in LambdaMOO.
Well, I'll record another draft of this later
after getting some feedback.
Or worse to worse, this is just what you'll hear.
Hopefully we have some questions and constructive comments.
All right, see everybody later.
Thank you so much for being here.
Please do drop in to my live show
if you're so inclined on Wednesdays
where you're not busy with cool Emacs conferences.
The list be go for climate.
Thank you to everyone who helped.
Thank you to Sacha
for really getting me into this conference
and kind of getting me going and
submitting this prerecorded talk.
See everybody later.