98 | 98 |
----------
|
99 | 99 |
|
100 | 100 |
Let's just go with pairs and atoms for now, although natural numbers would
|
101 | |
be easy to add too. Atoms are all-uppercase, and `TRUE` is the only truthy
|
102 | |
atom. Lists are by convention only (and by convention, lists compose via
|
103 | |
the second element of each pair, and `NIL` is the agreed-upon list-terminating
|
104 | |
atom, much love to it.)
|
|
101 |
be easy to add too. Following Ruby, atoms are preceded by a colon; while I
|
|
102 |
find this syntax somewhat obnoxious, it is less obnoxious than requiring that
|
|
103 |
atoms are in ALL CAPS, which is what Exanoke originally had. In truth, there
|
|
104 |
would be no real problem with allowing atoms, parameters, and function names
|
|
105 |
to all be arbitrarily alphanumeric, but it would require more static context
|
|
106 |
checking to sort them all out, and we're trying to be heavily syntactic here.
|
|
107 |
|
|
108 |
`:true` is the only truthy atom. Lists are by convention only, and, by
|
|
109 |
convention, lists compose via the second element of each pair, and `:nil` is
|
|
110 |
the agreed-upon list-terminating atom, much love to it.
|
105 | 111 |
|
106 | 112 |
Grammar
|
107 | 113 |
-------
|
|
117 | 123 |
| "cons?" "(" Expr ")"
|
118 | 124 |
| "not" "(" Expr ")"
|
119 | 125 |
| "#"
|
120 | |
| Atom
|
|
126 |
| ":" Ident
|
121 | 127 |
| Ident ["(" Expr {"," Expr} ")"]
|
122 | 128 |
| Smaller.
|
123 | 129 |
Smaller ::= "<head" SmallerTerm
|
|
125 | 131 |
| "<if" Expr "then" Smaller "else" Smaller.
|
126 | 132 |
SmallerTerm ::= "#"
|
127 | 133 |
| Smaller.
|
128 | |
Ident ::= name<lowercase>.
|
129 | |
Atom ::= name<uppercase>.
|
|
134 |
Ident ::= name.
|
130 | 135 |
|
131 | 136 |
The first argument to a function does not have a user-defined name; it is
|
132 | |
simply referred to as `#`.
|
|
137 |
simply referred to as `#`. Again, there would be no real problem if we were
|
|
138 |
to allow the programmer to give it a better name, but more static context
|
|
139 |
checking would be involved.
|
133 | 140 |
|
134 | 141 |
Note that `<if` does not seem to be truly necessary. Its only use is to embed
|
135 | 142 |
a conditional into the first argument being passed to a recursive call. You
|
136 | 143 |
could also use a regular `if` and make the recursive call in both branches,
|
137 | |
one with `TRUE` as the first argument and the other with `FALSE`.
|
|
144 |
one with `:true` as the first argument and the other with `:false`.
|
138 | 145 |
|
139 | 146 |
Examples
|
140 | 147 |
--------
|
|
146 | 153 |
|
147 | 154 |
Basic examples.
|
148 | 155 |
|
149 | |
| cons(HI, THERE)
|
150 | |
= (HI THERE)
|
|
156 |
| cons(:hi, :there)
|
|
157 |
= (:hi :there)
|
151 | 158 |
|
152 | |
| cons(HI, cons(THERE, NIL))
|
153 | |
= (HI (THERE NIL))
|
154 | |
|
155 | |
| head(cons(HI, THERE))
|
156 | |
= HI
|
157 | |
|
158 | |
| tail(cons(HI, THERE))
|
159 | |
= THERE
|
160 | |
|
161 | |
| tail(tail(cons(HI, cons(THERE, NIL))))
|
162 | |
= NIL
|
163 | |
|
164 | |
| tail(FOO)
|
|
159 |
| cons(:hi, cons(:there, :nil))
|
|
160 |
= (:hi (:there :nil))
|
|
161 |
|
|
162 |
| head(cons(:hi, :there))
|
|
163 |
= :hi
|
|
164 |
|
|
165 |
| tail(cons(:hi, :there))
|
|
166 |
= :there
|
|
167 |
|
|
168 |
| tail(tail(cons(:hi, cons(:there, :nil))))
|
|
169 |
= :nil
|
|
170 |
|
|
171 |
| tail(:foo)
|
165 | 172 |
? tail: Not a cons cell
|
166 | 173 |
|
167 | |
| head(BAR)
|
|
174 |
| head(:bar)
|
168 | 175 |
? head: Not a cons cell
|
169 | 176 |
|
170 | |
| <head cons(HI, THERE)
|
|
177 |
| <head cons(:hi, :there)
|
171 | 178 |
? Expected <smaller>, found "cons"
|
172 | 179 |
|
173 | |
| <tail HI
|
174 | |
? Expected <smaller>, found "HI"
|
175 | |
|
176 | |
| if TRUE then HI else THERE
|
177 | |
= HI
|
178 | |
|
179 | |
| if HI then HERE else THERE
|
180 | |
= THERE
|
181 | |
|
182 | |
| eq?(HI, THERE)
|
183 | |
= FALSE
|
184 | |
|
185 | |
| eq?(HI, HI)
|
186 | |
= TRUE
|
187 | |
|
188 | |
| cons?(HI)
|
189 | |
= FALSE
|
190 | |
|
191 | |
| cons?(cons(WAGGA, NIL))
|
192 | |
= TRUE
|
193 | |
|
194 | |
| not(TRUE)
|
195 | |
= FALSE
|
196 | |
|
197 | |
| not(FALSE)
|
198 | |
= TRUE
|
199 | |
|
200 | |
| not(cons(WANGA, NIL))
|
201 | |
= TRUE
|
|
180 |
| <tail :hi
|
|
181 |
? Expected <smaller>, found ":hi"
|
|
182 |
|
|
183 |
| if :true then :hi else :there
|
|
184 |
= :hi
|
|
185 |
|
|
186 |
| if :hi then :here else :there
|
|
187 |
= :there
|
|
188 |
|
|
189 |
| eq?(:hi, :there)
|
|
190 |
= :false
|
|
191 |
|
|
192 |
| eq?(:hi, :hi)
|
|
193 |
= :true
|
|
194 |
|
|
195 |
| cons?(:hi)
|
|
196 |
= :false
|
|
197 |
|
|
198 |
| cons?(cons(:wagga, :nil))
|
|
199 |
= :true
|
|
200 |
|
|
201 |
| not(:true)
|
|
202 |
= :false
|
|
203 |
|
|
204 |
| not(:false)
|
|
205 |
= :true
|
|
206 |
|
|
207 |
Cons cells are falsey.
|
|
208 |
|
|
209 |
| not(cons(:wanga, :nil))
|
|
210 |
= :true
|
|
211 |
|
|
212 |
`self` and `#` can only be used inside function definitions.
|
202 | 213 |
|
203 | 214 |
| #
|
204 | 215 |
? Use of "#" outside of a function body
|
205 | 216 |
|
206 | |
| self(FOO)
|
|
217 |
| self(:foo)
|
207 | 218 |
? Use of "self" outside of a function body
|
208 | 219 |
|
209 | 220 |
| def id(#)
|
210 | 221 |
| #
|
211 | |
| id(WOO)
|
212 | |
= WOO
|
|
222 |
| id(:woo)
|
|
223 |
= :woo
|
213 | 224 |
|
214 | 225 |
| def id(#)
|
215 | 226 |
| #
|
216 | |
| id(FOO, BAR)
|
|
227 |
| id(:foo, :bar)
|
217 | 228 |
? Arity mismatch (expected 1, got 2)
|
218 | 229 |
|
219 | 230 |
| def id(#)
|
220 | 231 |
| woo
|
221 | |
| id(WOO)
|
|
232 |
| id(:woo)
|
222 | 233 |
? Undefined argument "woo"
|
223 | 234 |
|
224 | 235 |
| def wat(#, woo)
|
225 | 236 |
| woo(#)
|
226 | |
| wat(WOO)
|
|
237 |
| wat(:woo)
|
227 | 238 |
? Undefined function "woo"
|
228 | 239 |
|
229 | 240 |
| def wat(#)
|
230 | |
| THERE
|
|
241 |
| :there
|
231 | 242 |
| def wat(#)
|
232 | |
| HI
|
233 | |
| wat(WOO)
|
|
243 |
| :hi
|
|
244 |
| wat(:woo)
|
234 | 245 |
? Function "wat" already defined
|
235 | 246 |
|
236 | |
| def WAT(#)
|
|
247 |
| def :wat(#)
|
237 | 248 |
| #
|
238 | |
| WAT(WOO)
|
239 | |
? Expected identifier, but found atom ('WAT')
|
|
249 |
| :wat(:woo)
|
|
250 |
? Expected identifier, but found atom (':wat')
|
240 | 251 |
|
241 | 252 |
| def wat(meow)
|
242 | 253 |
| meow
|
243 | |
| wat(WOO)
|
|
254 |
| wat(:woo)
|
244 | 255 |
? Expected '#', but found 'meow'
|
245 | 256 |
|
246 | 257 |
| def snd(#, another)
|
247 | 258 |
| another
|
248 | |
| snd(FOO, BAR)
|
249 | |
= BAR
|
|
259 |
| snd(:foo, :bar)
|
|
260 |
= :bar
|
250 | 261 |
|
251 | 262 |
| def snd(#, another)
|
252 | 263 |
| another
|
253 | |
| snd(FOO)
|
|
264 |
| snd(:foo)
|
254 | 265 |
? Arity mismatch (expected 2, got 1)
|
255 | 266 |
|
256 | 267 |
| def snoc(#, another)
|
257 | 268 |
| cons(another, #)
|
258 | |
| snoc(THERE, HI)
|
259 | |
= (HI THERE)
|
|
269 |
| snoc(:there, :hi)
|
|
270 |
= (:hi :there)
|
260 | 271 |
|
261 | 272 |
| def count(#)
|
262 | 273 |
| self(<tail #)
|
263 | |
| count(cons(A, cons(B, NIL)))
|
|
274 |
| count(cons(:alpha, cons(:beta, :nil)))
|
264 | 275 |
? tail: Not a cons cell
|
265 | 276 |
|
266 | 277 |
| def count(#)
|
267 | |
| if eq?(#, NIL) then NIL else self(<tail #)
|
268 | |
| count(cons(A, cons(B, NIL)))
|
269 | |
= NIL
|
|
278 |
| if eq?(#, :nil) then :nil else self(<tail #)
|
|
279 |
| count(cons(:alpha, cons(:beta, :nil)))
|
|
280 |
= :nil
|
270 | 281 |
|
271 | 282 |
| def last(#)
|
272 | 283 |
| if not(cons?(#)) then # else self(<tail #)
|
273 | |
| last(cons(A, cons(B, GRAAAP)))
|
274 | |
= GRAAAP
|
|
284 |
| last(cons(:alpha, cons(:beta, :graaap)))
|
|
285 |
= :graaap
|
275 | 286 |
|
276 | 287 |
| def count(#, acc)
|
277 | |
| if eq?(#, NIL) then acc else self(<tail #, cons(ONE, acc))
|
278 | |
| count(cons(A, cons(B, NIL)), NIL)
|
279 | |
= (ONE (ONE NIL))
|
|
288 |
| if eq?(#, :nil) then acc else self(<tail #, cons(:one, acc))
|
|
289 |
| count(cons(:A, cons(:B, :nil)), :nil)
|
|
290 |
= (:one (:one :nil))
|
|
291 |
|
|
292 |
Functions can call other user-defined functions.
|
280 | 293 |
|
281 | 294 |
| def double(#)
|
282 | 295 |
| cons(#, #)
|
283 | 296 |
| def quadruple(#)
|
284 | 297 |
| double(double(#))
|
285 | |
| quadruple(MEOW)
|
286 | |
= ((MEOW MEOW) (MEOW MEOW))
|
|
298 |
| quadruple(:meow)
|
|
299 |
= ((:meow :meow) (:meow :meow))
|
|
300 |
|
|
301 |
Functions must be defined before they are called.
|
287 | 302 |
|
288 | 303 |
| def quadruple(#)
|
289 | 304 |
| double(double(#))
|
290 | 305 |
| def double(#)
|
291 | 306 |
| cons(#, #)
|
292 | |
| MEOW
|
|
307 |
| :meow
|
293 | 308 |
? Undefined function "double"
|
294 | 309 |
|
295 | 310 |
Argument names may shadow previously-defined functions, because we
|
|
299 | 314 |
| cons(other, #)
|
300 | 315 |
| def snocsnoc(#, snoc)
|
301 | 316 |
| snoc(snoc(snoc, #), #)
|
302 | |
| snocsnoc(BLARCH, GLAMCH)
|
303 | |
= (BLARCH (BLARCH GLAMCH))
|
|
317 |
| snocsnoc(:blarch, :glamch)
|
|
318 |
= (:blarch (:blarch :glamch))
|
304 | 319 |
|
305 | 320 |
| def urff(#)
|
306 | 321 |
| self(<tail #, <head #)
|
307 | |
| urff(WOOF)
|
|
322 |
| urff(:woof)
|
308 | 323 |
? Arity mismatch on self (expected 1, got 2)
|
309 | 324 |
|
310 | 325 |
| def urff(#, other)
|
311 | 326 |
| self(<tail #)
|
312 | |
| urff(WOOF, MOO)
|
|
327 |
| urff(:woof, :moo)
|
313 | 328 |
? Arity mismatch on self (expected 2, got 1)
|
314 | 329 |
|
315 | 330 |
| def urff(#)
|
316 | 331 |
| self(cons(#, #))
|
317 | |
| urff(WOOF)
|
|
332 |
| urff(:woof)
|
318 | 333 |
? Expected <smaller>, found "cons"
|
319 | 334 |
|
320 | 335 |
| def urff(#)
|
321 | 336 |
| self(#)
|
322 | |
| urff(GRAAAAP)
|
|
337 |
| urff(:graaap)
|
323 | 338 |
? Expected <smaller>, found "#"
|
324 | 339 |
|
325 | 340 |
| def urff(#, boof)
|
326 | 341 |
| self(boof)
|
327 | |
| urff(GRAAAAP, SKOOOORP)
|
|
342 |
| urff(:graaap, :skooorp)
|
328 | 343 |
? Expected <smaller>, found "boof"
|
329 | 344 |
|
330 | 345 |
| def urff(#, boof)
|
331 | 346 |
| self(<tail boof)
|
332 | |
| urff(GRAAAAP, SKOOOORP)
|
|
347 |
| urff(:graaap, :skooorp)
|
333 | 348 |
? Expected <smaller>, found "boof"
|
334 | 349 |
|
335 | 350 |
| def urff(#)
|
336 | |
| self(WANGA)
|
337 | |
| urff(GRAAAAP)
|
338 | |
? Expected <smaller>, found "WANGA"
|
339 | |
|
340 | |
| def urff(#)
|
341 | |
| self(if eq?(A, A) then <head # else <tail #)
|
342 | |
| urff(GRAAAAP)
|
|
351 |
| self(:wanga)
|
|
352 |
| urff(:graaap)
|
|
353 |
? Expected <smaller>, found ":wanga"
|
|
354 |
|
|
355 |
| def urff(#)
|
|
356 |
| self(if eq?(:alpha, :alpha) then <head # else <tail #)
|
|
357 |
| urff(:graaap)
|
343 | 358 |
? Expected <smaller>, found "if"
|
344 | 359 |
|
345 | 360 |
| def urff(#)
|
346 | |
| self(<if eq?(A, A) then <head # else <tail #)
|
347 | |
| urff(GRAAAAP)
|
|
361 |
| self(<if eq?(:alpha, :alpha) then <head # else <tail #)
|
|
362 |
| urff(:graaap)
|
348 | 363 |
? head: Not a cons cell
|
349 | 364 |
|
350 | 365 |
| def urff(#)
|
351 | |
| self(<if eq?(self(<head #), A) then <head # else <tail #)
|
352 | |
| urff(GRAAAAP)
|
|
366 |
| self(<if eq?(self(<head #), :alpha) then <head # else <tail #)
|
|
367 |
| urff(:graaap)
|
353 | 368 |
? head: Not a cons cell
|
354 | 369 |
|
355 | 370 |
| def urff(#)
|
356 | 371 |
| self(<if self(<tail #) then <head # else <tail #)
|
357 | |
| urff(cons(GRAAAAP, FARRRRP))
|
|
372 |
| urff(cons(:graaap, :skooorp))
|
358 | 373 |
? tail: Not a cons cell
|
359 | 374 |
|
360 | 375 |
TODO
|