1 Core Syntactic Forms
Elle differs from other Lisps in that it uses several delimiters, each having a different meaning. Elle recognizes parentheses (), brackets [], and braces {} as delimiters. A syntactic form may assign arbitrary meaning to the delimiters, but each has an independent meaning, when used as part of a standalone expression:
parentheses are used for procedure application;
brackets are (currently) not used for anything and will result in a syntax error;
braces are used for “syntax application” (special forms and macros).
1.1 Definitions
Unlike most (if not all) Lisps, Elle does not have a parenthesized, prefix form for value definitions. Instead, Elle has an unparenthesized, infix form, similar to some languages outside the Lisp family.
syntax
val-pat = expr
proc-header ⇒ expr
proc-header = (name args) | (proc-header args) args = mandatory-args maybe-optional-args maybe-rest mandatory-args = val-pat ... #:<kw> val-pat ... ... maybe-optional-args =
| [val-pat ... #:<kw> val-pat ... ...] maybe-rest =
| id ...
The second form binds name to a procedure formed by unfolding the proc-header into a “curried λ”.
syntax
syntax
1.2 Patterns and Matching
syntax
literal
id {derived stx ...}
derived : match-expander?
syntax
(values pat ...)
pat
The second form is equivalent to (values pat).
1.2.1 Pattern Matching
syntax
{match expr match-clause ...+}
match-clause = pat ⇒ result-expr | pat #:guarded [guard-clause ...+] guard-clause = test-expr ⇒ result-expr
test-expr : boolean?
syntax
{match* [expr ...+] match*-clause ...+}
match*-clause = [pat ...+] ⇒ result-expr | [pat ...+] #:guarded [guard-clause ...+]
1.3 Procedures
The second form is syntactic sugar for nested λ forms, yielding a, “curried λ”.
syntax
(proc-expr arg ... maybe-rest)
arg = expr | #:<kw> expr maybe-rest =
| rest-expr ...
proc-expr : procedure?
rest-expr : list?
1.4 Local Binding
syntax
{let definition ...+ #:in expr}
1.5 Conditional Forms
syntax
{cond cond-clause ...+ maybe-else}
cond-clause = test-expr ⇒ then-expr maybe-else =
| #:else else-expr
test-expr : boolean?
1.6 Defining New Types
1.6.1 Algebraic Data Types
syntax
{define-type name type-case ...+ type-option ...}
type-case = enum-id | (tuple-id field-id ...) | (record-id #:field-kw ...) type-option = #:inspector inspector | #:property property expr
inspector : inspector?
property : struct-type-property?
name? is bound to a predicate that returns #true, if the given value is one of the type-cases; #false, otherwise;
each enum-id is bound to a unique value that is equal only to itself;
each tuple-id is bound to static information about the respective tuple case; it is also bound to a match-expander for constructing and destructuring values of the tuple case;
for each tuple-id, the name tuple-id? is bound to a predicate that returns #true, if the given value is an instance of tuple-id; #false, otherwise;
for each tuple-id, the name tuple-id-field-id is bound to a projection operation (accessor) for the respective field;
each record-id is bound to static information about the respective record case; it is also bound to a match-expander for constructing and destructuring values of the record case;
for each record-id, the name record-id? is bound to a predicate that returns #true, if the given value is an instance of record-id; #false, otherwise;
for each record-id, the name record-id-field-kw is bound to a projection operation (accessor) for the respective field.
1.6.2 Wrapper Types
syntax
{define-wrapper-type name type-option ...}
type-option = #:inspector inspector code:line = #:property | property | expr
inspector : inspector?
property : struct-type-property?
1.6.3 Object Types
syntax
{define-object-type name (#:field-kw ...) type-option}
type-option = #:inspector inspector | #:property property expr
inspector : inspector?
property : struct-type-property?