Wiki
Download
Manual
Eggs
API
Tests
Bugs
show
edit
history
You can edit this page using
wiki syntax
for markup.
Article contents:
== CHICKEN for Emacs Lisp programmers [[toc:]] If you're here, chances are that you want to go beyond Lisp as an extension language and use a general-purpose Lisp dialect. This guide has been written by [[https://github.com/wasamasa?utf8=✓&tab=repositories&q=&type=&language=emacs%20lisp|the author of a few outrageous Emacs packages]] [[https://github.com/wasamasa?utf8=✓&tab=repositories&q=&type=&language=scheme|who happens to write more serious projects in CHICKEN]]. == Programming paradigms Emacs Lisp is a fundamentally imperative language while Scheme leans towards the functional side of things. Nevertheless, it's possible to extend both towards other paradigms and steal APIs as seen in other languages. The most popular Emacs packages for this purpose happen to be {{cl-lib}} and [[https://github.com/magnars/dash.el|dash.el]], to get a taste of what's possible with CHICKEN, check out the [[http://wiki.call-cc.org/chicken-projects/egg-index-5.html|egg index]], specifically the "Language extensions" and "Object-oriented programming" sections. == Lisp-1 vs. Lisp-2 A more accurate title for this section would be "Lisp-1 vs. Lisp-n" as Emacs Lisp has more than two namespaces (faces live in symbol plists and can therefore not collide with other symbols). The Lisp-1 vs. Lisp-2 debate revolves around the question whether it should be possible to define a variable with the same name as a function without collisions. Lisp-1 dialects (such as Scheme, Clojure and Picolisp) disallow this whereas Lisp-2 dialects (such as Emacs Lisp and Common Lisp) allow it. This design decision leads to a number of differences, the most important one being how named functions are passed as values: <enscript lang="emacs-lisp"> (mapcar '1+ '(0 1 2)) ;=> (1 2 3) </enscript> The equivalent example in CHICKEN looks a bit different: <enscript lang="scheme"> (map add1 '(0 1 2)) ;=> (1 2 3) </enscript> If you haven't spotted it, unlike in Emacs Lisp, {{add1}} isn't quoted. In fact, quoting it yields an error: <enscript lang="scheme"> (map 'add1 '(0 1 2)) ;; Error: call of non-procedure: add1 add1 ;=> #<procedure (add1 n1097)> 'add1 ;=> add1 </enscript> It turns out that evaluating {{1+}} in Emacs Lisp gives one a "Void variable" error while evaluating {{add1}} in CHICKEN returns a procedure. From this one can deduce that {{mapcar}} in Emacs Lisp looks up the function value of the {{1+}} symbol while {{map}} in CHICKEN looks up the value of the {{add1}} symbol. For this reason CHICKEN doesn't offer a {{symbol-function}} procedure, you'll have to {{(eval 'add1)}} instead or better, pass the procedure instead of its quoted symbol. There are more differences arising from this: * Variables and functions are defined the same way. In fact, {{(define (foo) 42)}} is equivalent to {{(define foo (lambda () 42))}}. * There is no need for {{flet}} to temporarily define functions. You can use regular {{let}} and bind a lambda which you can call later. It's more common though to add an inner {{define}} for helper functions. * To call a "computed" function, one can simply put it at the head of the list. {{(funcall (if 42 '+ '-) 1 1)}} translates into {{((if 42 + -) 1 1)}}. * There is a greater risk for name collisions in (unhygienic) macros. * It's frowned upon to call a list argument {{list}} as that would shadow the built-in {{list}} procedure. == Dynamic vs. lexical binding Emacs Lisp defaults to dynamic binding for a number of reasons, the most important one being that doing so allows one to redefine nearly anything temporarily. While this is convenient in a text editor full of questionable defaults, it has the downside of making for slower compiled code and not allowing for lexical closures (which can be emulated with the {{lexical-let}} macro or by splicing in externally accessed values into a lambda). In CHICKEN lexical binding is the default which means that lexical closures are created when closing over free variables in a lambda. If you do need variables that behave as if dynamically bound, you can use the {{fluid-let}} macro or better, define [[http://api.call-cc.org/5/doc/chicken/base#sec:Parameters|parameters]]. == Truthiness Emacs Lisp has {{t}} as the canonical true value and {{nil}} as the canonical false value which doubles for the empty list, too. While it may look bizarre that {{()}} evaluates to {{nil}}, it's convenient to check this way whether a list is empty and to create a list by appending a value to {{nil}}. In the rare case when you need to tell {{nil}} apart from a non-empty list, you use the {{consp}} predicate over {{listp}}. In CHICKEN, the truthiness values are {{#t}} and {{#f}} for true and false, with the empty list being a separate, non-falsy value. In other words, everything except {{#f}} is truthy. Code that checks for the empty or non-empty list must use the {{null?}} and {{pair?}} predicates. While this makes for clearer code, it's a bit more annoying to type than the Emacs Lisp equivalent. Similarly, {{(car nil)}} in Emacs Lisp will happily give you {{nil}} while doing {{(car '())}} in Scheme yields an error. A separate issue is that in Emacs Lisp {{nil}} is frequently used as placeholder for the undefined value. {{(if nil t)}} evaluates to {{nil}}, the result of {{(if #f #t)}} however gives you the undefined value in CHICKEN. If you wish to use the result of this in a different procedure, it's better to be explicit to avoid incomprehensible errors. == Equality predicates Just like in Emacs Lisp, there's a plethora of equality predicates in CHICKEN. You'll typically want to use {{=}} (numbers), {{eqv?}} (identity) and {{equal?}} (structure). Depending on the situation, type-specific equality predicates might be useful, such as {{string=?}} and {{char=?}}. == Control flow === Sequencing {{progn}} in Emacs Lisp groups a body and evaluates to its last form, the CHICKEN equivalent is {{begin}}. If you ever feel like you need {{prog1}}, either use {{begin0}} from the [[http://api.call-cc.org/5/doc/miscmacros|miscmacros]] egg or {{(let ((result (first-form))) ... result)}}. === Simple conditionals {{if}} in Emacs Lisp has a ''then'' form and a ''else'' body, in Scheme both branches must be a single form and are indented by four spaces each. {{when}} and {{unless}} are provided in CHICKEN as well. === Generic conditionals {{cond}} looks slightly different in Scheme as the ''else'' case is specified by the {{else}} keyword. Furthermore, it's possible to transform the result of a test with the {{=>}} syntax, see [[http://wiki.call-cc.org/man/5/Module%20scheme|R5RS]] for further details. === Specialized conditionals Emacs Lisp doesn't offer {{case}} in its core, for that one people typically resort to {{cl-case}} (from {{cl-lib}}) or {{pcase}} (without using its pattern matching). CHICKEN has {{case}} and {{select}} which check whether an expression is {{eqv?}} to any of a given set of keys, with the difference between {{case}} and {{select}} being that the latter evaluates the keys to allow using variables. === Pattern matching Emacs Lisp has {{pcase}} whereas CHICKEN has [[http://api.call-cc.org/5/doc/matchable|matchable]]. Make sure to check out [[https://web.archive.org/web/20180721192553/http://ceaude.twoticketsplease.de/articles/an-introduction-to-lispy-pattern-matching.html|Moritz Heidkamp's blog post]] on it. === Simple loops The fundamental looping construct in Emacs Lisp is {{while}}, with {{throw}} and {{catch}} allowing one to terminate control flow early. Scheme does ''not'' have a direct equivalent as recursion and mandatory TCO are sufficient to express iteration in an elegant manner. When combined with the named let form, a simple while loop can be written as {{(let loop () (when (...) ... (loop)))}}. Further helpers for iteration can be found in SRFI-1, most importantly {{for-each}} (iterate across list), {{do}} (imperative iteration) and {{fold}} (generic iteration). While eggs providing complex loop macros do exist (including one implementing the infamous {{LOOP}} macro from Common Lisp), they aren't used much. == Custom types Emacs Lisp doesn't really have records. {{cl-defstruct}} emulates them by sticking values into a vector, with the downside that you can't define a printer method for your new type or reliably figure out the type of a "struct". In CHICKEN, you get not one, not two, but three(!) ways to define records. You'll most likely want to stick to {{define-record}}, alternatively {{define-record-type}} (as seen in SRFI-9) if you find {{define-record}} too magic or want to specify alternative names for getters and setters. Printers are taken care of with {{define-record-printer}}. Finally, there's SRFI-99 records which you must install separately, these give you a procedural interface which allows you to do fancy stuff like inheritance and introspection. As for CLOS-like libraries, the egg index has an entire section for these. COOPS seems to be the best, but I can't vouch for it. If none of them satisfies your needs, it's easy enough to roll your own (which would explain the wealth of options). == Standard library Consult the following before rolling your own: * [[http://wiki.call-cc.org/man/5/Module%20scheme|The R5RS standard]] * [[https://srfi.schemers.org/srfi-1/srfi-1.html|SRFI-1]] * [[http://api.call-cc.org/5/doc/chicken/modules/included|Built-in modules]] * [[http://wiki.call-cc.org/chicken-projects/egg-index-5.html|The egg index]] That being said, don't be afraid to roll your own. If you're considering to add one more dependency to your project, it might make more sense to bundle one function definition. It might also happen that there is no egg for what you want to use, so you might get to [[http://wiki.call-cc.org/eggs%20tutorial|write your own]] and [[http://wiki.call-cc.org/releasing-your-egg|share it with the rest of the world]]! == Modules While you can get away with writing scripts without worrying about those, it's recommended to use modules for bigger programs. This allows the compiler to find more mistakes for you (such as referring to unknown identifiers) and more importantly, to have namespaces when using the module from another file. These namespaces can be thought of as a set of identifiers which you create by using the {{import}} and {{use}} syntax. In other words, unlike in languages like Clojure, namespaces aren't like hashtables that you can modify freely after instantiation. It's possible to use extra qualifiers to selectively import or rename identifiers, see [[http://api.call-cc.org/5/doc/chicken/modules|the manual]] for details. == Editor integration The integration of Emacs Lisp into Emacs is unparalleled and one of the reasons why you'd want to pick this editor for your daily work. CHICKEN isn't nearly as integrated, for better (no chance for your hackery to corrupt your editor's internal state) or worse (more friction). Here's a list of possible workflows with Scheme and Emacs: * Editing sources in Emacs, evaluating and running code in an external terminal emulator. This is the most robust solution, but features the least amount of integration. * Using {{M-x run-scheme}} and sending code to the REPL. This workflow doesn't need any fancy setup and works reasonably well. * Using an external Emacs package such as [[https://github.com/jaor/geiser|Geiser]] for an IDE-like experience. This requires more setup and is rather fragile. If you're using Vim, [[http://wiki.call-cc.org/vim|the wiki]] provides helpful tips. For other text editors, the first workflow will have to do. == Buffers vs ports Buffers are the ubiquitious abstraction in Emacs. Whenever confronted with a text processing problem, one loads up the text into a (temporary) buffer, then navigates/edits it as needed to solve the task. CHICKEN's closest thing to this is the ports abstraction used for I/O, be it with strings, files, sockets, whatever. Refer to [[http://wiki.call-cc.org/man/5/Module%20scheme#input-and-output|The R5RS standard]] for details. == Communication with the outside world To interact with other programs, you have the following options: * Processes: Can be accomplished with the {{posix}} unit, the {{scsh-process}} egg makes things considerably easier. * Sockets: Use the {{tcp}} and {{udp}} units for this. * FFI: Interestingly enough, CHICKEN's approach to this is relatively close to Emacs modules, but much nicer because you don't have to write the whole thing in C. You'll want to study [[http://wiki.call-cc.org/man/5/Interface%20to%20external%20functions%20and%20variables|the manual]] for this and check out the {{foreigners}} and {{bind}} eggs. The {{lazy-ffi}} egg is another option if you prefer runtime FFI. == Macros Macros in Emacs Lisp are seemingly simple until you learn that they're unhygienic and require careful thought to not accidentally capture identifiers. Even more so if you ''do'' want to capture some of them and ensure nothing else is affected. CHICKEN offers more than one macro system, the default option is {{syntax-rules}} which combines pattern matching with hygiene, at the price of not being able to inject identifiers. Will Donelly wrote [[http://web.archive.org/web/20190406152238/http://www.willdonnelly.net/blog/scheme-syntax-rules/|a good tutorial]] on basic usage, [[http://www.phyast.pitt.edu/~micheles/syntax-rules.pdf|JRM's syntax-rules primer]] covers intermediate and advanced usage. Additionally to that CHICKEN comes with [[http://wiki.call-cc.org/man/5/Module%20(chicken%20syntax)|explicit and implicit renaming macros]] that allow you to inject identifiers on an opt-out or opt-in basis. [[http://wiki.call-cc.org/explicit-renaming-macros|Here's another tutorial]]. You might be wondering now whether to bother writing Scheme macros at all. In fact, things like the {{with-resource}} class of macros with a body argument aren't encountered often, instead procedures like {{with-input-from-string}} take a so-called ''thunk'', a zero argument procedure containing the body argument. Writing your own is simple thanks to functions being first-class and even encouraged to do as it allows for greater composability. == Tooling While Emacs Lisp tooling is weird, there are many useful things provided by vanilla Emacs and third-party packages, with a good level of editor integration. The situation isn't nearly as good with CHICKEN, your choice of tools is limited to the following: * Basic REPL ({{csi}}), optionally with readline-style editing: ** [[http://wiki.call-cc.org/eggref/4/parley|parley]] (to be ported) ** [[http://wiki.call-cc.org/eggref/5/linenoise|linenoise]] ** [[http://wiki.call-cc.org/eggref/5/breadline|breadline]] * [[http://www.more-magic.net/posts/statistical-profiling.html|Two profilers]] * [[http://wiki.call-cc.org/eggref/5/chicken-doc|chicken-doc]] * The {{feathers}} debugger: [[http://lists.gnu.org/archive/html/chicken-hackers/2015-11/msg00044.html]] Additionally to that you can attack the problem from the C side of things and use tools like {{gdb}} and {{valgrind}} to debug deeper-seated failure and memory leaks. People seeking for a more IDE-like experience are encouraged to give [[https://github.com/jaor/geiser|Geiser]] or the [[http://wiki.call-cc.org/eggref/4/slime|slime egg]] (to be ported) a try. == Application/library development The obvious way to create an application is by using {{csc}} to combine all input files as needed to one executable. This makes for less work than by using Makefiles, but can be tricky to get right, especially if you need to reference resource files. In this situation it can be of advantage to structure your application as an egg and use {{chicken-install}} to install it. Static linking got easier in CHICKEN 5 as the entire system and eggs are built both in dynamic and static versions. The only issues you'll be running into is bindings to external libraries. The vast majority of eggs consists of libraries pulled in from [[http://www.more-magic.net/posts/vcs-independent-distribution.html|distributed sources]]. There are tutorials about [[http://wiki.call-cc.org/eggs%20tutorial|writing]] and [[http://wiki.call-cc.org/releasing-your-egg|releasing]] eggs. If you want to study existing eggs for common solutions, I recommend downloading a local mirror with [[http://wiki.call-cc.org/running-an-egg-mirror#running-an-egg-mirror|henrietta-cache]]. Documentation isn't kept in the sources (for the lack of docstrings and a culture discouraging entanglement of documentation and code) and goes to [[http://wiki.call-cc.org/|the wiki]] instead. == Community The Emacs community is huge, but with a lot of code resting on the shoulders of a few skilled people. Most development activity revolves around the MELPA repository, where stability and the semblance of a sane development model is the exception. The core team does primarily use the {{emacs-devel}} mailing list for communication, but isn't particularly inviting to newcomers. CHICKEN's community is considerably smaller, but more welcoming. [[http://wiki.call-cc.org/chicken-projects/egg-index-5.html|The egg index]] serves as the central hub where one can install eggs from. If you encounter an egg outside it or write your own, you can simply run {{chicken-install}} in its directory. You can participate by hanging out on the {{#chicken}} channel and getting involved on the mailing lists. To get an idea how ''you'' can help out, check out the [[http://wiki.call-cc.org/contribute|contributing]] and [[http://wiki.call-cc.org/wish-list|wishlist]] wiki pages.
Description of your changes:
I would like to authenticate
Authentication
Username:
Password:
Spam control
What do you get when you multiply 2 by 7?