summaryrefslogtreecommitdiffstats
path: root/2025/talks/schemacs.md
blob: 1f13e06e70ed749aa13da9592f215f93dded7d2e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
[[!meta title="One year progress update Schemacs (formerly Gypsum)"]]
[[!meta copyright="Copyright © 2025 Ramin Honary"]]
[[!inline pages="internal(2025/info/schemacs-nav)" raw="yes"]]

<!-- Initially generated with emacsconf-publish-talk-page and then left alone for manual editing -->
<!-- You can manually edit this file to update the abstract, add links, etc. --->


# One year progress update Schemacs (formerly Gypsum)
Ramin Honary (he/him) - Pronunciation: "Rah-mean" (hard-H) "Ho-na-ree", Mastodon (preferred): ; blog: <https://tilde.town/~ramin_hal9001>; Codeberg: <https://codeberg.org/ramin_hal9001/schemacs> - SourceHut: <https://sr.ht/~ramin_hal9001>



[[!inline pages="internal(2025/info/schemacs-before)" raw="yes"]]

During EmacsConf 2024  last year I presented my  work on a
clone of GNU Emacs written in Scheme which also clones the
Emacs  Lisp programming  language.  In  this talk,  I will
briefly present an overview of  the project similar to the
talk I gave last year,  and then discuss the progress that
I have made on this project in the past year.

To quote the description from the presentation I gave last
year:

> Unlike  other   editors  which  only  clone   the  Emacs
> keybindings  (Edwin,  Jed,  jEdit, Jove,  Lem,  MG,  Yi,
> Zile), I hope  my Emacs clone will also  fully clone the
> Emacs Lisp programming language well enough that many of
> the  packages in  ELPA, Non-GNU  ELPA, and  perhaps even
> MELPA,  can be  used  in  [Schemacs, formerly  "Gypsum"]
> without any modification.   I would also like  to talk a
> little bit about how I  am implementing it (the software
> architecture), and invite others to contribute.
> 
> I think  my project is  of interest to many  Emacs users
> because,  firstly,  I  have  personally  spoken  with  a
> relatively  large number  of people  who have  expressed
> interest  in   making  Emacs  programmable   in  Scheme.
> Secondly, there is a good amount of prior art for Scheme
> implementations of Emacs. There are even builds of Emacs
> that  link  to  Guile  which  provides  a  "scheme-eval"
> built-in  function that  translates  between Elisp  data
> types and  Scheme data types. The  Guile compiler itself
> ships with an  Emacs Lisp compiler as  well, although it
> does not provide enough of Emacs's built-in functions to
> be of much use.

The progress I have made so far:

-   Ported  all  Guile-specific  parts  of  the  Emacs  Lisp
    interpreter  to  fully standards-compliant  R7RS  Scheme
    code.   The  interpreter now  runs  on  a few  different
    Scheme implementations, not just Guile.  The GUI remains
    Guile-only for now.

-   Implemented a new R7RS-compliant  lexer and parser which
    constructs an Abstract Syntax Tree (AST) data structure,
    making  it  easier to  find  the  source of  errors  and
    produce informative back traces.

-   Implemented enough  of the Emacs Lisp  interpreter to be
    able  to load  the "subr.el"  source file,  this defines
    what  you  might  call  the "core"  of  the  Emacs  Lisp
    language, including macros such as "defun" and "lambda."

My primary  goal continues  to be  to make  it as  easy as
possible   for  other   people  to   contribute  to   this
project.  Pretty soon  it should  be possible  to run  the
Emacs Regression Test suite (ERT) in the cloned Emacs Lisp
interpreter. Once this  is done, we can run  the same test
code used  during the  building and  testing GNU  Emacs to
test  Schemacs. Hopefilly  then,  anyone will  be able  to
select a failing  test, write code to make  the test pass,
and submit a patch.

About the speaker:

I am  Ramin Honary. I have been  professional software
engineer for 17 years and I  have always had a passion for
functional programming  languages, especially  Haskell and
the Lisp family of languages.

## Discussion / notes

-   Q: I think that Kiczalez et al.'s metaobject protocol has a scheme
    implementation, does this mean schemacs will be
    metaobject-changeable in practice? 
    -   A: I was not aware of that implementation, but I will look into
        it. The MOP has not been necessary for building the GUI,
        actually (apart from the fact that Guile-GI uses GOOPS to
        organize the Gtk3 bindings). Pretty soon I will demonstrate the
        React-like programming framework I have developed for the
        Schemacs GUI.
    -   A: I don't need a meta-object protocol for Schemacs, at least
        so far it hasn't been necessary, but may be something to look
        into if it can be made cross-platform (for various R7RS
        Schemes).
-   Q: How will the GUI display code be r7rs compliant afaik there is no
    dlopen in r7rs?
    -   A: To handle these platform-dependent concerns, I make heavy use
        of the `cond-expand` macro. Basically any Scheme
        implementation upon which I would like to run the Schemacs GUI
        will have to have it's own unique back-end code that is
        loaded-in to the main Scheme program. `cond-expand` has
        mechanisms for checking which Scheme implementation it is using,
        so it is pretty easy to write code that can load-in different
        back-ends for whatever platform you are using.
-   Q: Will it be possible to write multithreaded code for Schemacs?
    -   A: The GUI is inherently single-threaded, but SRFI-18 provides
        multi-threading. So yes, there is multi-threading, and I do have
        ways of evaluating Scheme code inside of the GUI thread so that
        you can update the GUI. This is necessary for running external
        processes and putting the results into buffers. But anyone
        should be able to use the threading mechanism through the
        ordinary SRFI-18 APIs.
        [https://srfi.schemers.org/srfi-18/srfi-18.html](https://srfi.schemers.org/srfi-18/srfi-18.html)
-   Q: Do you think some of schemacs could be extracted into SRFIs since
    you have made it portable between scheme implementations?
    -   A: Absolutely. I have considered making a SRFI for my
        `(schemacs lens)` library. I would like to break up the
        Schemacs into libraries and publish them on the Akku package
        manager, or in the Guix repository. I am hopeful that some of
        the libraries I have written will be useful for other Scheme
        programmers.
        [https://akkuscm.org/](https://akkuscm.org/)
-   Q: Is there a recommended scheme implementation or does it try to be
    as portable as possible?
    -   A:(He said earlier that Guile was the only version that worked
        so far.  He wants it to work for all R7RS though.) That's
        right, Guile is the reference implementation, the GUI only works
        on Guile, but Emacs Lisp works on Guile, Chibi, and Gauche. I
        would like to support as many Scheme's as possible. If you want
        to get started with Scheme and you want to try Schemacs, I
        recommend Guile.
-   Q: How would Schemacs deal with Emacs' (re)display architecture?
    Would it be having its own display architecture? If so, how can it
    be compatible with things like overlays, images, etc.? From what I
    know, Emacs is extremely idiosyncratic here.
    -   A: That is all "to be determined." At some point we will have
        to emulate the Emacs Lisp display architecture in Schemacs, but
        for the time being Schemacs has it's own completely different
        display architecture.
-   Q: You were saying that you'd like to get "most" of the one
    thousand three hundred and something Emacs packages done. Is there a
    technical blocker to doing them all? Or just a problem of getting
    enough people in to help and start writing scheme?
    -   A: just a matter of implementing enough of Emacs' built-in
        functions; this relates to the bug we saw in the presentation
        (stack dump); other people will have trouble contributing until
        this is resolved because it does not handle closures correctly. 
        once that is worked out it will be a matter of implementing
        Emacs' C-based functions in scheme.  Don't have a way to be
        sure but we probably do not need all of them implemented.
-   Q: What are you thoughts on Chicken Scheme? Would it be a good fit?
    -   A: I think it will be; tried this in preping for the
        presentation but ran into some issues; tried using the pattern
        matcher from Alex Shinn; each implementation has a slightly
        different take on macro-expansion for pattern matching; I would
        definitely love help in this area. I will probably have to avoid
        pattern matching to make it fully portable, or else implement my
        own pattern matcher which I can be sure will work on all R7RS
        Scheme implementations.
-   Q: Can this emacs lisp implementation be used by Guile's emacs lisp
    "mode"?
    -   A: This was touched on last year; Emacs Lisp in guile is a
        different implemtation which is unfortunately quite incomplete,
        it can't even run some of the GNU Emacs initialization code. 
        When I first started I was using Guile Emacs Lisp's parser,
        however it did not give source locations, and was not portable
        to other Schemes, so I had to basically write everything for
        Schemacs from the ground-up. If Andy Wingo is interested, we can
        probably replace the existing Guile Emacs Lisp implementation
        with Schemacs.
-   Q: I wonder if we could do some sort of programmatic analysis on
    popular Emacs packages to see what list of functions they tend to
    depend upon, follow function calls down to the lowest level
    -   A:  Yes, please do this for me! :D :D
-   Q: Shouldn't it be enough to just implement the builtin functions?
    Most of the commands are written in Emacs Lisp, right?
    -   A: Yes, correct. That is the approach I am taking. My goal is to
        get the Emacs Regression Test suite (ERT) system working in
        Schemacs Emacs Lisp, then we can just use the reports generated
        by the GNU Emacs regression tests to see what Emacs Lisp
        functions we have left to implement in Schemacs.
-   Q:  Do you think there is an opportunity to use Racket?
    -   A: Yes, looking at getting Schemacs working Chez then could
        somehow move onto Racket; haven't tried R7RS for racket. Racket
        works on Chez, and I would like to make Schemacs work on Chez,
        but I won't be able to make use of Racket libraries. Alexis
        King has written a R7RS language package for Racket, and I
        haven't tried it yet, but it may be a good way to get Schemacs
        to work in Racket.
-   Q: Tell us more about this show-stopping bug! How to squash it? Can
    people help?
    -   A: Unfortunately, this is something I will have to do on my own
        unless you happen to be a Scheme genius who can read and
        understand all of my code so far in a short amount of time. It
        has to do with how closures work. Closures were introduced with
        Emacs 27 (?) and lexical scoped variables for ELisp.  When we
        create and return a lambda that uses a variable declared outside
        of the Lambda in a "let" binding, that variable resides on the
        stack, so the Lambda must have a "note" that captures part of
        the current stack and then later restores it when the Lambda is
        executed. This is where the issue is: it is not capturing the
        variables from the stack properly.  The plan is to do static
        analysis of the Lambda and then store a reference to those
        vairbles in the Lambda data structure.
        -   Q: How about using smaller test cases (instead of a full
            Emacs loadup) to pinpoint the issue? When writing Juicemacs
            I've gather a few closure-related test cases
            ([https://github.com/gudzpoz/Juicemacs/blob/ddc61c08632cfdd1a9f2bc10f63e61c5679d6592/elisp/src/test/java/party/iroiro/juicemacs/elisp/runtime/ELispBindingScopeTest.java#L12-L91](https://github.com/gudzpoz/Juicemacs/blob/ddc61c08632cfdd1a9f2bc10f63e61c5679d6592/elisp/src/test/java/party/iroiro/juicemacs/elisp/runtime/ELispBindingScopeTest.java#L12-L91)
            , and some more test cases in a blog post:
            [https://kyo.iroiro.party/en/posts/emacs-lisp-interpreter-with-graalvm-truffle/#creating-closures-in-a-loop](https://kyo.iroiro.party/en/posts/emacs-lisp-interpreter-with-graalvm-truffle/#creating-closures-in-a-loop)
            ). Could they be useful? (I just tried to take a peek at
            Schemacs' code, but I'm really not familiar with
            Scheme...)
        -   By the way, Emacs comes with its own static analyzer in
            elisp (cconv.el) that seems to select captured variables
            from env cons lists in Emacs, which might be useful if
            you're also using a cons/linked list of lexical bindings, I
            guess?
-   Q: Are there performance concerns with implementing certain C
    primitives in pure scheme?
    -   A: No :) I think it was Donald Knuth who said "Premature
        optimization is the root of all evil." The graphical back-end
        is usually written in C anyway (Gtk3), so the graphics is being
        done in C. Besides that, Scheme compilers like Guile, Chez,
        Gambit, and Chicken all have very good performance
        characteristics. So for the time being, I don't think
        performance is a major concern.
-   Q:  If this project is successful, are you worried about a possible
    split in the community between Schemacs and GNU Emacs users?
    -   A: There seems to be a large call for a scheme based editor, so
        the demand for this "split" is already there. There have been
        attempts at rewriting Emacs in Scheme since the early 90s. And
        there hasn't been a good, free-software, Scheme-based
        programming environment like Emacs since Edwin on MIT Scheme. 
        So Schemacs may cause some fragmentation but "a rising tide
        raises all ships".  If I have time I would also like to
        contribute some of what I learn from Schemacs back to GNU Emacs,
        for example I would like to work on an interactive canvas
        library based on the "Cairo" SVG rendering library. Cairo is
        already built-in to Emacs, so I would like to maybe port my
        Schemacs interactive canvas (still a work in progress) to GNU
        Emacs when I have some time.
-   Q:  The dream of never even needing to change to the web browser -
    would schemacs bring us closer to that?
    -   A: I hope so!  this is also a dream of mine!  I wanted to make
        sure I have a good workable UI framework like React so we can
        write proper GUIs for applications such as a Mastadon client, it
        could be very nice to have a better GUI for this, or for Magit,
        or Gnus. I would love to be able to do as much as possible in
        Schemacs, e.g. social networking, public Git repos. That is a
        goal of mine for this project.
-   Q: Anything specific other than minimalism that made you choose
    Scheme over Common Lisp?
    -   A: Philosophical question :)  I love Haskell, and I once had a
        conversation with William Byrd (author of "MiniKanren," who
        studied under Dan Friedman at the University of Indiana) who
        told me about why he didn't like Haskell and suggested looking
        into Scheme. I like Haskell because it is a very pure
        implementation of the "System-F" Lambda Calculus, and I like
        Scheme because it's closer to the mathematical framework of the
        Untyped Lambda Calculus, but Scheme is friendly (without the
        strict type system), similar to Python. It provides a tiny
        framework from which all of computer science can be explored. 
        Excited to see what this tiny language can do. I like the idea
        of starting from a tiny "kernel" language and using it to
        build-out all other alglorithms and software. I think it is a
        shame that there isn't much Scheme code out there, and I would
        like to try to expand the Scheme software ecosystem.
-   [https://codeberg.org/ramin_hal9001/schemacs](https://codeberg.org/ramin_hal9001/schemacs)
-   [https://github.com/spk121/guile-gi](https://github.com/spk121/guile-gi) 
    <-- that is the GUI back-end, by the way.
-   [https://gi.readthedocs.io/en/latest/](https://gi.readthedocs.io/en/latest/)  
    <-- that is GObject Introspection, this is how the GUI bindings
    work.
-   lol it feels like rahim has been standing at the same place since
    last year :P
-   Basically, yes, I haven't moved at all! Of course I have moved away
    from that spot in the interim once or twice.
-   Awesome talk, I will surely try to contribute even though I don't
    know stuff yet :)
    -   All are welcome, if you don't know anything, I'll be happy to
        try and teach you!


- amazing progress
- nice talk.
- I'm so excited for this project! Amazing update 😊
- I wonder if we could do some sort of programmatic analysis on popular Emacs packages to see what list of functions they tend to depend upon, follow function calls down to the lowest level
- would love to see that
- That is probably a good idea (getting rid of the baggage)




[[!inline pages="internal(2025/info/schemacs-after)" raw="yes"]]

[[!inline pages="internal(2025/info/schemacs-nav)" raw="yes"]]