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

Last change on this file since 39377 was 39377, checked in by gnosis, 8 months ago

Fixed broken link

File size: 17.2 KB
[34071]1== CHICKEN for Emacs Lisp programmers
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
9author of a few outrageous Emacs packages]]
11happens to write more serious projects in CHICKEN]].
13== Programming paradigms
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 [[|dash.el]], to
20get a taste of what's possible with CHICKEN, check out the
22index]], specifically the "Language extensions" and "Object-oriented
23programming" sections.
25== Lisp-1 vs. Lisp-2
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:
38<enscript lang="emacs-lisp">
39(mapcar '1+ '(0 1 2)) ;=> (1 2 3)
42The equivalent example in CHICKEN looks a bit different:
44<enscript lang="scheme">
45(map add1 '(0 1 2)) ;=> (1 2 3)
48If you haven't spotted it, unlike in Emacs Lisp, {{add1}} isn't
49quoted.  In fact, quoting it yields an error:
51<enscript lang="scheme">
52(map 'add1 '(0 1 2))
53;; Error: call of non-procedure: add1
55add1 ;=> #<procedure (add1 n1097)>
56'add1 ;=> add1
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.
68There are more differences arising from this:
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.
84== Dynamic vs. lexical binding
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).
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
100== Truthiness
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}}.
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
[34075]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.
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.
126== Equality predicates
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=?}}.
134== Control flow
136=== Sequencing
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
[37688]141[[|miscmacros]] egg or
[34071]142{{(let ((result (first-form))) ... result)}}.
144=== Simple conditionals
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.
150=== Generic conditionals
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
[37688]155[[|R5RS]] for further
158=== Specialized conditionals
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.
167=== Pattern matching
169Emacs Lisp has {{pcase}} whereas CHICKEN has
[37688]170[[|matchable]].  Make sure to
[34071]171check out
[34071]173Heidkamp's blog post]] on it.
175=== Simple loops
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)))}}.
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.
190== Custom types
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
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).
210== Standard library
212Consult the following before rolling your own:
[37688]214* [[|The R5RS
[34071]215  standard]]
216* [[|SRFI-1]]
[37688]217* [[|Built-in modules]]
218* [[|The egg
[34071]219  index]]
221That being said, don't be afraid to roll your own.  If you're
222considering to add one more dependency to your project, it might make
223more sense to bundle one function definition.  It might also happen
224that there is no egg for what you want to use, so you might get to
225[[|write your own]] and
226[[|share it with the rest of
227the world]]!
229== Modules
231While you can get away with writing scripts without worrying about
232those, it's recommended to use modules for bigger programs.  This
233allows the compiler to find more mistakes for you (such as referring
234to unknown identifiers) and more importantly, to have namespaces when
235using the module from another file.  These namespaces can be thought
236of as a set of identifiers which you create by using the {{import}}
237and {{use}} syntax.  In other words, unlike in languages like Clojure,
238namespaces aren't like hashtables that you can modify freely after
239instantiation.  It's possible to use extra qualifiers to selectively
240import or rename identifiers, see
[37688]241[[|the manual]] for
244== Editor integration
246The integration of Emacs Lisp into Emacs is unparalleled and one of
247the reasons why you'd want to pick this editor for your daily work.
248CHICKEN isn't nearly as integrated, for better (no chance for your
249hackery to corrupt your editor's internal state) or worse (more
250friction).  Here's a list of possible workflows with Scheme and Emacs:
252* Editing sources in Emacs, evaluating and running code in an external
253  terminal emulator.  This is the most robust solution, but features
254  the least amount of integration.
255* Using {{M-x run-scheme}} and sending code to the REPL.  This
256  workflow doesn't need any fancy setup and works reasonably well.
257* Using an external Emacs package such as
258  [[|Geiser]] for an IDE-like
259  experience.  This requires more setup and is rather fragile.
261If you're using Vim, [[|the wiki]] provides
262helpful tips.  For other text editors, the first workflow will have to
265== Buffers vs ports
267Buffers are the ubiquitious abstraction in Emacs.  Whenever confronted
268with a text processing problem, one loads up the text into a
269(temporary) buffer, then navigates/edits it as needed to solve the
270task.  CHICKEN's closest thing to this is the ports abstraction used
271for I/O, be it with strings, files, sockets, whatever.  Refer to
[34071]273R5RS standard]] for details.
275== Communication with the outside world
277To interact with other programs, you have the following options:
279* Processes: Can be accomplished with the {{posix}} unit, the
280  {{scsh-process}} egg makes things considerably easier.
281* Sockets: Use the {{tcp}} and {{udp}} units for this.
282* FFI: Interestingly enough, CHICKEN's approach to this is relatively
283  close to Emacs modules, but much nicer because you don't have to
284  write the whole thing in C.  You'll want to study
[37688]285  [[|the
[34071]286  manual]] for this and check out the {{foreigners}} and {{bind}}
287  eggs.  The {{lazy-ffi}} egg is another option if you prefer runtime
288  FFI.
290== Macros
292Macros in Emacs Lisp are seemingly simple until you learn that they're
293unhygienic and require careful thought to not accidentally capture
294identifiers.  Even more so if you ''do'' want to capture some of them
295and ensure nothing else is affected.  CHICKEN offers more than one
296macro system, the default option is {{syntax-rules}} which combines
297pattern matching with hygiene, at the price of not being able to
298inject identifiers.  Will Donelly wrote
299[[|a good
300tutorial]] on basic usage,
302syntax-rules primer]] covers intermediate and advanced usage.
303Additionally to that CHICKEN comes with
305and implicit renaming macros]] that allow you to inject identifiers on
306an opt-out or opt-in basis.
307[[|Here's another
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.
318== Tooling
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:
325* Basic REPL ({{csi}}), optionally with readline-style editing:
[37688]326** [[|parley]] (to be ported)
327** [[|linenoise]]
328** [[|breadline]]
[34071]329* [[|Two profilers]]
[37688]330* [[|chicken-doc]]
[34071]331* The {{feathers}} debugger: [[]]
333Additionally to that you can attack the problem from the C side of
334things and use tools like {{gdb}} and {{valgrind}} to debug
335deeper-seated failure and memory leaks.
337People seeking for a more IDE-like experience are encouraged to give
338[[|Geiser]] or the
[37688]339[[|slime egg]] (to be ported) a
342== Application/library development
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
[37688]349{{chicken-install}} to install it.  Static linking got easier in
350CHICKEN 5 as the entire system and eggs are built both in dynamic and
351static versions.  The only issues you'll be running into is
352bindings to external libraries.
354The vast majority of eggs consists of libraries pulled in from
356sources]].  There are tutorials about
357[[|writing]] and
358[[|releasing]] eggs.  If you
359want to study existing eggs for common solutions, I recommend
360downloading a local mirror with
362Documentation isn't kept in the sources (for the lack of docstrings
363and a culture discouraging entanglement of documentation and code) and
364goes to [[|the wiki]] instead.
[34073]366== Community
368The Emacs community is huge, but with a lot of code resting on the
369shoulders of a few skilled people.  Most development activity revolves
370around the MELPA repository, where stability and the semblance of a
371sane development model is the exception.  The core team does primarily
372use the {{emacs-devel}} mailing list for communication, but isn't
373particularly inviting to newcomers.
375CHICKEN's community is considerably smaller, but more welcoming.
[37688]376[[|The egg
[34071]377index]] serves as the central hub where one can install eggs from.  If
378you encounter an egg outside it or write your own, you can simply run
379{{chicken-install}} in its directory.  You can participate by hanging
380out on the {{#chicken}} channel and getting involved on the mailing
381lists.  To get an idea how ''you'' can help out, check out the
382[[|contributing]] and
[36801]383[[|wishlist]] wiki pages.
Note: See TracBrowser for help on using the repository browser.