Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 234 lines (167 sloc) 7.555 kb
c3995fb @VincentToups extended readme
authored
1 Clojure-like Emacs
2 ------------------
3
4 This is a group of loosely organized utilities to add clojure like
5 abilities to emacs-lisp.
6
7 It consists of defn and fn forms for declaring functions and anonymous
8 functions. These forms support the usual clojure-style destructuring
9 bind and arity based dispatch on function arguments. Another macro,
10 dlet, implements destructuring bind for "let". All of them are
11 lexically scoped, rather than the emacs default dynamic scope.
12 Despite this, a defn function is an emacs function, and can be
13 declared interactive.
14
15 defn, fn, dlet examples
16 -----------------------
17
18 These work in a manner similar to the clojure equivalents.
19
a1d79a4 @VincentToups fixed typo
authored
20 (require 'defn)
21
c3995fb @VincentToups extended readme
authored
22 (defn f
23 ([x] x)
24 ([x y] (* x y)))
25 (f 10) ; -> 10
26 (f 10 20) ; -> 200
27
28 This defines a function of one or two arguments. When the function is
29 called, the correct body is invoked based on arity.
30
31 While emacs lacks a special syntax for tables, it does have hash
32 tables. This library supports destructuring bind on hash-tables also
33 via the following syntax:
34
35 (defn f [a
36 [:: z :z :or (tbl! :z 100)]]
37 (list a z))
38
39 (f 10 (tbl! :z 11)) -> (10 11)
40 (f 10 (tbl!)) -> (10 100)
41
42
43 Note that `(tbl! :z 10)` is short hand which creates a hash table. It
d0011bf @VincentToups fixed typo
authored
44 can take multiple arguments: `(tbl! :x 10 :y 11 :z 14)`. Quick access
45 to the values in the table is accomplished via `tbl`: `(tbl
46 a-table:x)` gives the value stored by `:x`. These functions are
a1d79a4 @VincentToups fixed typo
authored
47 included in the library.
c3995fb @VincentToups extended readme
authored
48
49 Destructuring bind is fully recursive, so you can nest desctructuring
50 syntax deeply and the macros will do the right thing. The macro
51 `dlet` works as you expect:
52
53 (dlet [x 10 y 11] (+ x y)) ;-> 21
54
61ac1b3 @VincentToups recur added
authored
55 All of them create lexical scopes. An alternative set of forms create
56 dynamic scopes instead. These are available as `fn_`, `defn_` and
57 `dlet_`.
58
59 Functions and the `dloop` and `dloop_` forms create recursion points
60 so that the `recur` form causes a non-stack increasing recursion.
61 This is implemented via a codewalking macro and the new `dsetq` form,
62 which takes the same kind of input as a let, but setqs the values
63 instead of creating a scope. With these extensions you can write:
64
65 (dloop [x 0 output nil]
66 (if (> x 10) (reverse output)
67 (recur (+ x 1) (cons x output))))
68
69 Which evaluates to '(0 1 2 3 4 5 6 7 8 9 10). Functions create
70 implicit loop points, so you can implement the product function like
71 so:
72
73 (defn prod
74 ([[val & rest :as lst] acc]
75 (if (not lst) acc
76 (recur rest (* val acc))))
77 ([lst]
78 (prod lst 1)))
79
80 Recur does not cause stack to be consumed. It compiles into the loop
81 macro. Anonymous functions also support `recur`.
c3995fb @VincentToups extended readme
authored
82
83 Monads!
84 -------
85
86 I've implemented primitive monad support using this library. These
87 monads are patterned after the clojure contrib monad implementation
88 (although they are substantially less complete). Monads use the same
89 syntax for binding as clojure, so you can do neat things with them.
90
91 A simple example is the Identity monad.
92
93 (require 'monads)
94
95 (domonad monad-id [x 1 y 2] (+ x y)) ;-> 3
96
97 Slightly more interesting is the Maybe monad.
98
99 (domonad monad-maybe
100 [x (Just 20)
101 k (maybe/ x 4)
102 y (maybe+ k 1)]
e474af2 @VincentToups fixed typo
authored
103 y) ;-> (Just 6)
c3995fb @VincentToups extended readme
authored
104
105 But:
106
107 (domonad monad-maybe
108 [x (Just 20)
109 k (maybe/ x 0) ; Divide by zero ruins the calculation
110 y (maybe+ k 1)]
a1d79a4 @VincentToups fixed typo
authored
111 y) ;-> (None)
c3995fb @VincentToups extended readme
authored
112
113 Even more interesting is the sequence monad:
114
115 (domonad monad-seq
116 [x (list 1 2 3)
117 y (list 4 5 6)]
118 (list x y)) ;-> ((1 4) (1 5) (1 6) (2 4) (2 5) (2 6) (3 4) (3 5) (3 6))
119
120 Note that destructuring bind works with the monads:
121
122 (domonad monad-seq
123 [[a b] (list '(1 2) '(3 4) '(5 6))]
124 (+ a b)) ;-> (3 7 11)
125
126 This is built on top of the fn implementation, so all the
127 desctructuring supported there works here.
128
129 The implementation is wacky right now, but will be cleaned up when I
130 can find moments of respite from writing my dissertation.
131
132 Updates:
133 --------
bb18ea6 @VincentToups fixed recur expansion in let-likes, made non-recursive fns more effic…
authored
134 Update 19 Apr 2010
135
136 * fixed a bug in the expansion of recur wherein tail-calls inside
137 let-like forms (let, let*, lexical-let, lexical-let*, labels, flet)
138 would not expand.
139 * Improved the fn and fn_ macros so that they do not compile to loops
140 if recur is not used in their bodies. This is a tradeoff between
141 compilation and execution speed.
c3995fb @VincentToups extended readme
authored
142
61ac1b3 @VincentToups recur added
authored
143 Update 16 Mar 2010
144
145 * finally implemented recur keywords. Also implemented a
146 destructuring set operation. Added a dloop macro.
147
a77a5ea @VincentToups added state monad
authored
148 Update 28 Aug 2009
149
150 * added State Monad (monad-state).
151
c3995fb @VincentToups extended readme
authored
152 Update 26 Aug 2009
153
154 * fixed a regression in defn code which disabled the ability to make defn's interactive.
155 * ADDED MONADS!!!
156 * identity monad
157 * maybe monad
158 * sequence monad
159 * Monads support clojure-style destructuring bind via domonad expressions.
160 * no support for with-monad yet.
161
162
163 Update 17 July 2009
164
165 * fixed bug in dlet which caused an error with using the let*-like semantics. dlet is now a recursive macro
166 * todo: re-implement fn in terms of dlet. Still will require special handling of the top-level form.
167
168 Update 15 July 2009
169
170 * fixed bug wherein empty arg-lists would give an error.
171
172 Update 9 June 2009
173 * added support for :or forms for sequence binding types.
174 * Note: You can't use them at the top-level binder because they would confuse the automatic dispatch of function bodies on arity. Sorry.
175
176 Update 8 June 2009
177 * added support for :keys in table binder, corrected several small bugs introduced by new parsing code.
178
179 Update 7 June 2009
180 * rewrote binder parsing code so that it is easier to extend and support error checking
181 * added support for :or forms in table binders. The form after :or is evaluated at call-time, rather than compile time, and must result in a hash-table with the appropriate keys to provide defaults.
182
183 (defn f [a [:: z :z :or (tbl! :z 100)]] (list a z))
184 (f 10 (tbl! :z 11)) -> (10 11)
185 (f 10 (tbl!)) -> (10 100)
186
187
188 Update 2 June 2009
189 * added extensive checking of binder forms at compile time and what are hopefully informative error messages.
190 * Todo
191 - add support for :or form to the table destructuring
192
193 Update 1 June 2009
194 * defn now expands in terms of the fn macro
195 * lots more error checking. Some simple checks for misformed binders, also checks for arity when the function is called.
196
197 Update 31 May 2009
198 * added support for multiple arity defn and fn definitions:
199
200 (defn f
201 ([x] x)
202 ([x y] (* x y)))
203 (f 10) ; -> 10
204 (f 10 20) ; -> 200
205
206
207
208 Some emacs utilities with clojure-style destructuring bind.
209
210 (defn demo [a b [c d]] (list a b c d))
211 (demo 1 2 (list 10 11)) -> (1 2 10 11)
212
213 The binding also works with hashtables.
214
215 (defn demo [a b [:: c :x d :y]] (list a b c d))
216 (let ((a-table (tbl! :x 100 :y 110)))
217 (demo 1 2 a-table)) -> (1 2 100 110)
218
219 Most useful in the utils package may be a pair of functions for creating and manipulating hash tables.
220
221 (tbl! :x 10 :y 11) ; creates a hash table with keys :x, :y and associated values
222 (tbl a-table :x) ; returns the value at key :x
223
ab9dc24 @VincentToups defn fixes, more stack language
authored
224 Update 5 June 2010
9b284ac @VincentToups Monadic parser update, bug fixes.
authored
225 * Corrected a bug in defn expansion with recur.
226
227 Update 10 Oct 2010
228 * added lots of bug fixes, codewalking macros and functions to help
229 write them, `capturing-defun` and `capturing-lambda` which attempt to
230 meaningfully capture their apparent lexical scope (don't really work)
231 * added lex-lambda and lex-defun which automatically create lexical
232 scopes around their bodies containing their args.
233 * implemented monadic parser combinators using the monads in monads.el
234 * added lots more stack language functions.
Something went wrong with that request. Please try again.