source: project/wiki/chicken-for-emacs-lisp-programmers @ 34075

Last change on this file since 34075 was 34075, checked in by wasamasa, 2 years ago

Mention differences between Emacs Lisp and Scheme when accessing the car of null

File size: 17.5 KB
Line 
1== CHICKEN for Emacs Lisp programmers
2
3[[toc:]]
4
5If you're here, chances are that you want to go beyond Lisp as an
6extension language and use a general-purpose Lisp dialect.  This guide
7has been written by
8[[https://github.com/wasamasa?utf8=✓&tab=repositories&q=&type=&language=emacs%20lisp|the
9author of a few outrageous Emacs packages]]
10[[https://github.com/wasamasa?utf8=✓&tab=repositories&q=&type=&language=scheme|who
11happens to write more serious projects in CHICKEN]].
12
13== Programming paradigms
14
15Emacs Lisp is a fundamentally imperative language while Scheme leans
16towards the functional side of things.  Nevertheless, it's possible to
17extend both towards other paradigms and steal APIs as seen in other
18languages.  The most popular Emacs packages for this purpose happen to
19be {{cl-lib}} and [[https://github.com/magnars/dash.el|dash.el]], to
20get a taste of what's possible with CHICKEN, check out the
21[[http://wiki.call-cc.org/chicken-projects/egg-index-4.html|egg
22index]], specifically the "Language extensions", "Logic programming"
23and "Object-oriented programming" sections.
24
25== Lisp-1 vs. Lisp-2
26
27A more accurate title for this section would be "Lisp-1 vs. Lisp-n" as
28Emacs Lisp has more than two namespaces (faces live in symbol plists
29and can therefore not collide with other symbols).  The Lisp-1
30vs. Lisp-2 debate revolves around the question whether it should be
31possible to define a variable with the same name as a function without
32collisions.  Lisp-1 dialects (such as Scheme, Clojure and Picolisp)
33disallow this whereas Lisp-2 dialects (such as Emacs Lisp and Common
34Lisp) allow it.  This design decision leads to a number of
35differences, the most important one being how named functions are
36passed as values:
37
38<enscript lang="emacs-lisp">
39(mapcar '1+ '(0 1 2)) ;=> (1 2 3)
40</enscript>
41
42The equivalent example in CHICKEN looks a bit different:
43
44<enscript lang="scheme">
45(map add1 '(0 1 2)) ;=> (1 2 3)
46</enscript>
47
48If you haven't spotted it, unlike in Emacs Lisp, {{add1}} isn't
49quoted.  In fact, quoting it yields an error:
50
51<enscript lang="scheme">
52(map 'add1 '(0 1 2))
53;; Error: call of non-procedure: add1
54
55add1 ;=> #<procedure (add1 n1097)>
56'add1 ;=> add1
57</enscript>
58
59It turns out that evaluating {{1+}} in Emacs Lisp gives one a "Void
60variable" error while evaluating {{add1}} in CHICKEN returns a
61procedure.  From this one can deduce that {{mapcar}} in Emacs Lisp
62looks up the function value of the {{1+}} symbol while {{map}} in
63CHICKEN looks up the value of the {{add1}} symbol.  For this reason
64CHICKEN doesn't offer a {{symbol-function}} procedure, you'll have to
65{{(eval 'add1)}} instead or better, pass the procedure instead of its
66quoted symbol.
67
68There are more differences arising from this:
69
70* Variables and functions are defined the same way.  In fact,
71  {{(define (foo) 42)}} is equivalent to {{(define foo (lambda ()
72  42))}}.
73* There is no need for {{flet}} to temporarily define functions.  You
74  can use regular {{let}} and bind a lambda which you can call later.
75  It's more common though to add an inner {{define}} for helper
76  functions.
77* To call a "computed" function, one can simply put it at the
78  head of the list.  {{(funcall (if 42 '+ '-) 1 1)}} translates into
79  {{((if 42 + -) 1 1)}}.
80* There is a greater risk for name collisions in (unhygienic) macros.
81* It's frowned upon to call a list argument {{list}} as that would
82  shadow the built-in {{list}} procedure.
83
84== Dynamic vs. lexical binding
85
86Emacs Lisp defaults to dynamic binding for a number of reasons, the
87most important one being that doing so allows one to redefine nearly
88anything temporarily.  While this is convenient in a text editor full
89of questionable defaults, it has the downside of making for slower
90compiled code and not allowing for lexical closures (which can be
91emulated with the {{lexical-let}} macro or by splicing in externally
92accessed values into a lambda).
93
94In CHICKEN lexical binding is the default which means that lexical
95closures are created when closing over free variables in a lambda.  If
96you do need variables that behave as if dynamically bound, you can use
97the {{fluid-let}} macro or better, define
98[[http://api.call-cc.org/doc/chicken/parameters|parameters]].
99
100== Truthiness
101
102Emacs Lisp has {{t}} as the canonical true value and {{nil}} as the
103canonical false value which doubles for the empty list, too.  While it
104may look bizarre that {{()}} evaluates to {{nil}}, it's convenient to
105check this way whether a list is empty and to create a list by
106appending a value to {{nil}}.  In the rare case when you need to tell
107{{nil}} apart from a non-empty list, you use the {{consp}} predicate
108over {{listp}}.
109
110In CHICKEN, the truthiness values are {{#t}} and {{#f}} for true and
111false, with the empty list being a separate, non-falsy value.  In
112other words, everything except {{#f}} is truthy.  Code that checks for
113the empty or non-empty list must use the {{null?}} and {{pair?}}
114predicates.  While this makes for clearer code, it's a bit more
115annoying to type than the Emacs Lisp equivalent.  Similarly, {{(car
116nil)}} in Emacs Lisp will happily give you {{nil}} while doing {{(car
117'())}} in Scheme yields an error.
118
119A separate issue is that in Emacs Lisp {{nil}} is frequently used as
120placeholder for the undefined value.  {{(if nil t)}} evaluates to
121{{nil}}, the result of {{(if #f #t)}} however gives you the undefined
122value in CHICKEN.  If you wish to use the result of this in a
123different procedure, it's better to be explicit to avoid
124incomprehensible errors.
125
126== Equality predicates
127
128Just like in Emacs Lisp, there's a plethora of equality predicates in
129CHICKEN.  You'll typically want to use {{=}} (numbers), {{eqv?}}
130(identity) and {{equal?}} (structure).  Depending on the
131situation, type-specific equality predicates might be useful, such as
132{{string=?}} and {{char=?}}.
133
134== Control flow
135
136=== Sequencing
137
138{{progn}} in Emacs Lisp groups a body and evaluates to its last form,
139the CHICKEN equivalent is {{begin}}.  If you ever feel like you need
140{{prog1}}, either use {{begin0}} from the
141[[http://api.call-cc.org/doc/miscmacros#def:begin0|miscmacros]] egg or
142{{(let ((result (first-form))) ... result)}}.
143
144=== Simple conditionals
145
146{{if}} in Emacs Lisp has a ''then'' form and a ''else'' body, in
147Scheme both branches must be a single form and are indented by four
148spaces each.  {{when}} and {{unless}} are provided in CHICKEN as well.
149
150=== Generic conditionals
151
152{{cond}} looks slightly different in Scheme as the ''else'' case is
153specified by the {{else}} keyword.  Furthermore, it's possible to
154transform the result of a test with the {{=>}} syntax, see
155[[http://wiki.call-cc.org/man/4/The%20R5RS%20standard|R5RS]] for
156further details.
157
158=== Specialized conditionals
159
160Emacs Lisp doesn't offer {{case}} in its core, for that one people
161typically resort to {{cl-case}} (from {{cl-lib}}) or {{pcase}}
162(without using its pattern matching).  CHICKEN has {{case}} and
163{{select}} which check whether an expression is {{eqv?}} to any of a
164given set of keys, with the difference between {{case}} and {{select}}
165being that the latter evaluates the keys to allow using variables.
166
167=== Pattern matching
168
169Emacs Lisp has {{pcase}} whereas CHICKEN has
170[[http://api.call-cc.org/doc/matchable|matchable]].  Make sure to
171check out
172[[http://ceaude.twoticketsplease.de/articles/an-introduction-to-lispy-pattern-matching.html|Moritz
173Heidkamp's blog post]] on it.
174
175=== Simple loops
176
177The fundamental looping construct in Emacs Lisp is {{while}}, with
178{{throw}} and {{catch}} allowing one to terminate control flow early.
179Scheme does ''not'' have a direct equivalent as recursion and
180mandatory TCO are sufficient to express iteration in an elegant
181manner.  When combined with the named let form, a simple while loop
182can be written as {{(let loop () (when (...) ... (loop)))}}.
183
184Further helpers for iteration can be found in SRFI-1, most importantly
185{{for-each}} (iterate across list), {{do}} (imperative iteration) and
186{{fold}} (generic iteration).  While eggs providing complex loop
187macros do exist (including one implementing the infamous {{LOOP}}
188macro from Common Lisp), they aren't used much.
189
190== Custom types
191
192Emacs Lisp doesn't really have records.  {{cl-defstruct}} emulates
193them by sticking values into a vector, with the downside that you
194can't define a printer method for your new type or reliably figure out
195the type of a "struct".  In CHICKEN, you get not one, not two, but
196three(!) ways to define records.  You'll most likely want to stick to
197{{define-record}}, alternatively {{define-record-type}} (as seen in
198SRFI-9) if you find {{define-record}} too magic or want to specify
199alternative names for getters and setters.  Printers are taken care of
200with {{define-record-printer}}.  Finally, there's SRFI-99 records
201which you must install separately, these give you a procedural
202interface which allows you to do fancy stuff like inheritance and
203introspection.
204
205As for CLOS-like libraries, the egg index has an entire section for
206these.  COOPS seems to be the best, but I can't vouch for it.  If none
207of them satisfies your needs, it's easy enough to roll your own (which
208would explain the wealth of options).
209
210== Standard library
211
212Consult the following before rolling your own:
213
214* [[http://wiki.call-cc.org/man/4/The%20R5RS%20standard|The R5RS
215  standard]]
216* [[https://srfi.schemers.org/srfi-1/srfi-1.html|SRFI-1]]
217* [[http://wiki.call-cc.org/man/4/Supported%20language|Extensions and
218  built-in units]], especially the data-structures unit
219* [[http://wiki.call-cc.org/chicken-projects/egg-index-4.html|The egg
220  index]]
221
222That being said, don't be afraid to roll your own.  If you're
223considering to add one more dependency to your project, it might make
224more sense to bundle one function definition.  It might also happen
225that there is no egg for what you want to use, so you might get to
226[[http://wiki.call-cc.org/eggs%20tutorial|write your own]] and
227[[http://wiki.call-cc.org/releasing-your-egg|share it with the rest of
228the world]]!
229
230== Modules
231
232While you can get away with writing scripts without worrying about
233those, it's recommended to use modules for bigger programs.  This
234allows the compiler to find more mistakes for you (such as referring
235to unknown identifiers) and more importantly, to have namespaces when
236using the module from another file.  These namespaces can be thought
237of as a set of identifiers which you create by using the {{import}}
238and {{use}} syntax.  In other words, unlike in languages like Clojure,
239namespaces aren't like hashtables that you can modify freely after
240instantiation.  It's possible to use extra qualifiers to selectively
241import or rename identifiers, see
242[[http://wiki.call-cc.org/man/4/Modules#import|the manual]] for
243details.
244
245== Editor integration
246
247The integration of Emacs Lisp into Emacs is unparalleled and one of
248the reasons why you'd want to pick this editor for your daily work.
249CHICKEN isn't nearly as integrated, for better (no chance for your
250hackery to corrupt your editor's internal state) or worse (more
251friction).  Here's a list of possible workflows with Scheme and Emacs:
252
253* Editing sources in Emacs, evaluating and running code in an external
254  terminal emulator.  This is the most robust solution, but features
255  the least amount of integration.
256* Using {{M-x run-scheme}} and sending code to the REPL.  This
257  workflow doesn't need any fancy setup and works reasonably well.
258* Using an external Emacs package such as
259  [[https://github.com/jaor/geiser|Geiser]] for an IDE-like
260  experience.  This requires more setup and is rather fragile.
261
262If you're using Vim, [[http://wiki.call-cc.org/vim|the wiki]] provides
263helpful tips.  For other text editors, the first workflow will have to
264do.
265
266== Buffers vs ports
267
268Buffers are the ubiquitious abstraction in Emacs.  Whenever confronted
269with a text processing problem, one loads up the text into a
270(temporary) buffer, then navigates/edits it as needed to solve the
271task.  CHICKEN's closest thing to this is the ports abstraction used
272for I/O, be it with strings, files, sockets, whatever.  Refer to
273[[http://wiki.call-cc.org/man/4/The%20R5RS%20standard#input-and-output|The
274R5RS standard]] for details.
275
276== Communication with the outside world
277
278To interact with other programs, you have the following options:
279
280* Processes: Can be accomplished with the {{posix}} unit, the
281  {{scsh-process}} egg makes things considerably easier.
282* Sockets: Use the {{tcp}} and {{udp}} units for this.
283* FFI: Interestingly enough, CHICKEN's approach to this is relatively
284  close to Emacs modules, but much nicer because you don't have to
285  write the whole thing in C.  You'll want to study
286  [[http://wiki.call-cc.org/man/4/Interface%20to%20external%20functions%20and%20variables|the
287  manual]] for this and check out the {{foreigners}} and {{bind}}
288  eggs.  The {{lazy-ffi}} egg is another option if you prefer runtime
289  FFI.
290
291== Macros
292
293Macros in Emacs Lisp are seemingly simple until you learn that they're
294unhygienic and require careful thought to not accidentally capture
295identifiers.  Even more so if you ''do'' want to capture some of them
296and ensure nothing else is affected.  CHICKEN offers more than one
297macro system, the default option is {{syntax-rules}} which combines
298pattern matching with hygiene, at the price of not being able to
299inject identifiers.  Will Donelly wrote
300[[http://www.willdonnelly.net/blog/scheme-syntax-rules/|a good
301tutorial]] on basic usage,
302[[http://www.phyast.pitt.edu/~micheles/syntax-rules.pdf|JRM's
303syntax-rules primer]] covers intermediate and advanced usage.
304Additionally to that CHICKEN comes with
305[[http://wiki.call-cc.org/man/4/Macros|explicit and implicit renaming
306macros]] that allow you to inject identifiers on an opt-out or opt-in
307basis.  [[http://wiki.call-cc.org/explicit-renaming-macros|Here's
308another tutorial]].
309
310You might be wondering now whether to bother writing Scheme macros at
311all.  In fact, things like the {{with-resource}} class of macros with
312a body argument aren't encountered often, instead procedures like
313{{with-input-from-string}} take a so-called ''thunk'', a zero argument
314procedure containing the body argument.  Writing your own is simple
315thanks to functions being first-class and even encouraged to do as it
316allows for greater composability.
317
318== Tooling
319
320While Emacs Lisp tooling is weird, there are many useful things
321provided by vanilla Emacs and third-party packages, with a good level
322of editor integration.  The situation isn't nearly as good with
323CHICKEN, your choice of tools is limited to the following:
324
325* Basic REPL ({{csi}}), optionally with readline-style editing:
326** [[http://wiki.call-cc.org/eggref/4/parley]]
327** [[http://wiki.call-cc.org/eggref/4/linenoise]]
328** [[http://wiki.call-cc.org/eggref/4/readline]]
329** [[https://github.com/wasamasa/readline]] (cleaner alternative to the previous one with better tab-completion)
330* [[http://www.more-magic.net/posts/statistical-profiling.html|Two profilers]]
331* [[http://wiki.call-cc.org/eggref/4/chicken-doc|Documentation look-up]]
332* The {{feathers}} debugger: [[http://lists.gnu.org/archive/html/chicken-hackers/2015-11/msg00044.html]]
333
334Additionally to that you can attack the problem from the C side of
335things and use tools like {{gdb}} and {{valgrind}} to debug
336deeper-seated failure and memory leaks.
337
338People seeking for a more IDE-like experience are encouraged to give
339[[https://github.com/jaor/geiser|Geiser]] or the
340[[http://wiki.call-cc.org/eggref/4/slime|slime egg]] a try.
341
342== Application/library development
343
344The obvious way to create an application is by using {{csc}} to
345combine all input files as needed to one executable.  This makes for
346less work than by using Makefiles, but can be tricky to get right,
347especially if you need to reference resource files.  In this situation
348it can be of advantage to structure your application as an egg and use
349{{chicken-install}} to install it.  Deployment can be made to work,
350but is awkward, especially if it's of the static kind and external
351libraries are involved as every dependency needs to be built
352[[http://www.foldling.org/scheme.html#compiling-statically-linked-chicken-scheme-programs-with-extensions|the
353same way]].  This will hopefully be easier to do in the upcoming major
354release of CHICKEN.
355
356The vast majority of eggs consists of libraries pulled in from
357[[http://www.more-magic.net/posts/vcs-independent-distribution.html|distributed
358sources]].  There are tutorials about
359[[http://wiki.call-cc.org/eggs%20tutorial|writing]] and
360[[http://wiki.call-cc.org/releasing-your-egg|releasing]] eggs.  If you
361want to study existing eggs for common solutions, I recommend
362downloading a local mirror with
363[[http://wiki.call-cc.org/running-an-egg-mirror#running-an-egg-mirror|henrietta-cache]].
364Documentation isn't kept in the sources (for the lack of docstrings
365and a culture discouraging entanglement of documentation and code) and
366goes to [[http://wiki.call-cc.org/|the wiki]] instead.
367
368== Community
369
370The Emacs community is huge, but with a lot of code resting on the
371shoulders of a few skilled people.  Most development activity revolves
372around the MELPA repository, where stability and the semblance of a
373sane development model is the exception.  The core team does primarily
374use the {{emacs-devel}} mailing list for communication, but isn't
375particularly inviting to newcomers.
376
377CHICKEN's community is considerably smaller, but more welcoming.
378[[http://wiki.call-cc.org/chicken-projects/egg-index-4.html|The egg
379index]] serves as the central hub where one can install eggs from.  If
380you encounter an egg outside it or write your own, you can simply run
381{{chicken-install}} in its directory.  You can participate by hanging
382out on the {{#chicken}} channel and getting involved on the mailing
383lists.  To get an idea how ''you'' can help out, check out the
384[[http://wiki.call-cc.org/contribute|contributing]] and
385[[http://wiki.call-cc.org/wish-list|wishlist]] wiki pages.
Note: See TracBrowser for help on using the repository browser.