LFE Documentation User Guide Note \{\{ ... \}\} is use to denote optional syntax. Special syntactic rules ----------------------- #b #o #d #x #23r - Based integers #(e e ... ) - Tuple constants #b(e e ... ) - Binary constant, e ... are valid literals segments [ ... ] - Allowed as alternative to ( ... ) Supported Core forms -------------------- (quote e) (cons head tail) (car e) (cdr e) (list e ... ) (tuple e ... ) (binary seg ... ) (lambda (arg ...) ...) (match-lambda ((arg ... ) \{\{(when e ...)\}\} ...) - Matches clauses ... ) (let ((pat \{\{(when e ...)\}\} e) ...) ... ) (let-function ((name lambda|match-lambda) - Only define local functions ... ) ... ) (letrec-function ((name lambda|match-lambda) - Only define local functions ... ) ... ) (let-macro ((name lambda-match-lambda) - Only define local macros ...) ...) (progn ... ) (if test true-expr \{\{false-expr\}\}) (case e (pat \{\{(when e ...)\}\} ...) ... )) (receive (pat \{\{(when e ...)\}\} ... ) ... (after timeout ... )) (catch ... ) (try e \{\{(case ((pat \{\{(when e ...)\}\} ... ) ... ))\}\} \{\{(catch (((tuple type value ignore) \{\{(when e ...)\}\} - Must be tuple of length 3 here! ... ) ... )\}\} \{\{(after ... )\}\}) (funcall func arg ... ) (call mod func arg ... ) - Call to Mod:Func(Arg, ... ) (define-function name lambda|match-lambda) (define-macro name lambda|match-lambda) Define functions/macros at top-level. Supported macro forms --------------------- (: mod func arg ... ) => (call 'mod 'func arg ... ) (? \{\{timeout \{\{default\}\} \}\}) - Receive next message, optional timeout and default value (++ ... ) (list* ...) (let* (...) ... ) - Sequential let's (flet ((name (arg ...) ...) ...) ...) (flet* (...) ... ) - Sequential flet's (fletrec ((name (arg ...) ...) ...) ...) Define local functions, this will expand to lambda or match-lambda depending on structure as with defun. (cond ... ) - The normal cond, with (?= pat expr) (andalso ... ) (orelse ... ) (fun func arity) - fun func/arity (fun mod func arity) - fun mod:func/arity (lc (qual ...) ...) - [ expr || qual ... ] (bc (qual ...) ...) - << expr || qual ... >> (match-spec ...) - ets:fun2ms(fun ( ) -> end) Common Lisp inspired macros --------------------------- (defun name (arg ...) ...) (defun name ((argpat ...) ...) ...) Define a toplevel function, this will expand to lambda or match-lambda depending on structure. (defmacro name (arg ...) ...) (defmacro name arg ...) (defmacro name ((argpat ...) ...) ...) Define a top-level macro, this will expand to lambda or match-lambda depending on structure. (defsyntax name (pat exp) ...) Define a top-level macro using Scheme inspired syntax-rules format. (macrolet ((name (arg ...) ...) ...) ...) (syntaxlet ((name (pat exp) ...) ...) ...) Define local macros in macro or syntax-rule format. (defmodule name ...) (defrecord name ...) Older Scheme inspired macros ---------------------------- (define (name arg ...) ...) (define name lambda|match-lambda) (define-syntax name (syntax-rules (pat exp) ...)|(macro (pat body) ...)) (let-syntax ((name ...) ...) ...) (begin ...) (define-module name ...) (define-record name ...) Patterns -------- Written as normal data expressions where symbols are variables and use quote to match explicit values. Binaries and tuples have special syntax. {ok,X} -> (tuple 'ok x) error -> 'error {yes,[X|Xs]} -> (tuple 'yes (cons x xs)) <<34,F/float>> -> (binary 34 (f float)) [P|Ps]=All -> (= (cons p ps) all) Repeated variables are *NOT* supported in patterns, there is no automatic comparison of values. It must explicitly be done in a guard. _ as the "don't care" variable is supported. This means that the symbol _, which is a perfectly valid symbol, can never be bound through pattern matching. Aliases are defined with the (= pattern1 pattern2) pattern. As in Erlang patterns they can be used anywhere in a pattern. *CAVEAT* The lint pass of the compiler checks for aliases and if they are possible to match. If not an error is flagged. This is not the best way. Instead there should be a warning and the offending clause removed, but later passes of the compiler can't handle this yet. Guards ------ Wherever a pattern occurs (let, case, receive, lc, etc.) it can be followed by an optional guard which has the form (when test ...). Guard tests are the same as in vanilla Erlang and can contain the following guard expressions: (quote e) (cons gexpr gexpr) (car gexpr) (cdr gexpr) (list gexpr ...) (tuple gexpr ...) (binary ...) (progn gtest ...) - Sequence of guard tests (if gexpr gexpr gexpr) (type-test e) (guard-bif ...) - Guard BIFs, arithmetic, boolean and comparison operators An empty guard, (when), always succeeds as there is no test which fails. This simplifies writing macros which handle guards. Bindings and Scoping -------------------- LFE is a Lisp-2 and has separate namespaces for variables and functions/macros. Both variables and functions/macros are lexically scoped. Variables are bound by lambda, match-lambda and let, functions are bound by top-level defun, flet and fletrec, macros are bound by top-level defmacro/defsyntax and by macrolet/syntaxlet. When searching for function both name and arity are used, a macro is considered to have any arity and will match all functions with that name. While this is not consistent with either Scheme (or CL) it is simple, usually easy to understand and fits Erlang quite well. It does, however, require using (funcall func arg ... ) like CL to call lambdas/match-lambdas (funs) bound to variables. Core solves this by having separate bindings and special to have only one apply: apply _F (...) and apply _F/3 ( a1, a2, a3 ). Function shadowing ------------------ Unqualified functions shadow as stated above which results in the following order within a module, outermost to innermost: Predefined BIFs (same as in vanilla Erlang) Predefined LFE BIFs Imports Top-level defines Flet/fletrec This means that it is perfectly legal to shadow BIFs by imports, BIFs/imports by top-level functions and BIFs/imports/top-level by fletrecs. In this respect there is nothing special about BIfs, they just behave as prefined imported functions, a whopping big (import (from erlang ...)). EXCEPT that we know about guard BIFs and expression BIFs. If you want a private version of spawn then define it, there will be no warnings. *CAVEAT* This does not hold for the supported core forms. These can be shadowed by imports or redefined but the compiler will *always* use the core meaning and never an alternative. Silently! Module definition ----------------- (defmodule name (export (f 2) (g 1) ... ) (export all) ;Export all functions (import (from mod (f1 2) (f2 1) ... ) (rename mod ((f1 2) sune) ((f2 1) kurt) ... )) (import (prefix mod mod-prefix)) - NYI (attr-1 value-1 value-2) ... ) Can have multiple export and import declarations within module declaration. The (export all) declaration is allowed together with other export declarations and overrides them. Other attributes which are not recognised by the compiler are allowed and are simply passed on to the module and can be accessed through module_info/0-1. Parameterized modules --------------------- (defmodule (name par1 par2 ... ) ... ) Define a parameterized module which behaves the same way as in vanilla Erlang. For now avoid defining functions 'new' and 'instance'. Macros ------ Macro calls are expanded in both body and patterns. This can be very useful to have both make and match macros, but be careful with names. A macro is function of two argument which is a called with a list of the arguments to the macro call and the current macro environment. It can be either a lambda or a match-lambda. The basic forms for defining macros are: (define-macro name lambda|match-lambda) (let-macro ((name lambda|match-lambda) ...) Macros are definitely NOT hygienic in any form. To simplify writing macros there are a number of predefined macros: (defmacro name (arg ...) ...) (defmacro name arg ...) (defmacro name ((argpat ...) body) ...) Defmacro can be used for defining simple macros or sequences of matches depending on whether the arguments are a simple list of symbols or can be interpreted as a list of pattern/body pairs. In the second case when the argument is just a symbol it will be bound to the whole argument list. For example: (defmacro double (a) `(+ ,a ,a)) (defmacro my-list args `(list ,@args)) (defmacro andalso ((list e) `,e) ((cons e es) `(if ,e (andalso ,@es) 'false)) (() `'true)) The macro definitions in a macrolet obey the same rules as defmacro. The macro functions created by defmacro and macrolet automatically add the second argument with the current macro environment with the name $ENV. This allows explicit expansion of macros inside the macro and also manipulation of the macro environment. No changes to the environment are exported outside the macro. User defined macros shadow the predefined macros so it is possible to redefine the built-in macro definitions. However, see the caveat below! Yes, we have the backquote. It is implemented as a macro so it is expanded at macro expansion time. Local functions that are only available at compile time and can be called by macros are defined using eval-when-compile: (defmacro foo (x) ... (foo-helper m n) ...) (eval-when-compile (defun foo-helper (a b) ...) ) There can be many eval-when-compile forms. Functions defined within an eval-when-compile are mutually recursive but they can only call other local functions defined in an earlier eval-when-compile and macros defined earlier in the file. Functions defined in eval-when-compile which are called by macros can defined after the macro but must be defined before the macro is used. Scheme's syntax rules are an easy way to define macros where the body is just a simple expansion. These are supported with defsyntax and syntaxlet. Note that the patterns are only the arguments to the macro call and do not contain the macro name. So using them we would get: (defsyntax andalso (() 'true) ((e) e) ((e . es) (case e ('true (andalso . es)) ('false 'false)))) N.B. These are definitely NOT hygienic. *CAVEAT* While it is perfectly legal to define a Core form as a macro these will silently be ignored by the compiler. Extended cond ------------- Cond has been extended with the extra test (?= pat expr) which tests if the result of expr matches pat. If so it binds the variables in pat which can be used in the cond. A optional guard is allowed here. An example: (cond ((foo x) ...) ((?= (cons x xs) (when (is_atom x)) (bar y)) (fubar xs (baz x))) ((?= (tuple 'ok x) (baz y)) (zipit x)) ... ) Records ------- Records are tuples with the record name as first element and the rest of the fields in order exactly like "normal" Erlang records. As with Erlang records the default default value is 'undefined'. (defrecord name field (field default-value) ... ) Will create access functions/macros for creation and accessing fields. The make, match and set forms takes optional argument pairs field-name value to get non-default values. E.g. for (defrecord person (name '"") (address '"") age) => (make-person \{\{field value\}\} ... ) (match-person \{\{field value\}\} ... ) (is-person r) (emp-person \{\{field value\}\} ... ) (set-person r \{\{field value\}\} ... ) (person-name r) (set-person-name r name) (person-age r) (set-person-age r age) (person-address r) (set-person-address r address) (make-person name '"Robert" age 54) Will create a new person record with the name field set to "Robert", the age field set to 54 and the address field set to the default "". (match-person name name age 55) Will match a person with age 55 and bind the variable name to the name field of the record. Can use any variable name here. (is-person john) Test if john is a person record. (emp-person age '$1) Create an Ets Match Pattern for record person where the age field is set to $1 and all other fields are set to '_. (person-address john) Return the address field of the person record john. (set-person-address john '"back street") Sets the address field of the person record john to "back street". (set-person john age 35 address '"front street") In the person record john set the age field to 35 and the address field to "front street". Binaries/bitstrings ------------------- A binary is (binary seg ... ) where seg is byte string (val integer|float|binary|bitstring|bytes|bits (size n) (unit n) big-endian|little-endian|native-endian|little|native|big signed|unsigned) Val can also be a string in which case the specifiers will be applied to every character in the string. As strings are just lists of integers these are also valid here. In a binary constant all literal forms are allowed on input but they will always be written as bytes. List/binary comprehensions -------------------------- List/binary comprehensions are supported as macros. The syntax for list comprehensions is: (lc (qual ...) expr ... ) where the final expr is used to generate the elements of the list. The syntax for binary comprehensions is: (bc (qual ...) expr ... ) where the final expr is a bitseg expr and is used to generate the elements of the binary. The supported qualifiers, in both list/binary comprehensions are: (<- pat \{\{guard\}\} list-expr) - Extract elements from a list expression (<= bin-pat \{\{guard\}\} binary-expr) - Extract elements from a binary/bits expression (?= pat \{\{guard\}\} expr) - Match test and bind variables in pat expr - Normal boolean test Some examples: (lc ((<- v l1) (when (> v 5)) (== (rem v 2) 0)) v) returns a list of all the even elements of the list l1 which are greater than 5. (bc ((<= (f float (size 32)) b1) ;No wrapping, only bitseg needed (> f 10.0)) (: io fwrite '"~p\n" (list f)) (f float (size 64))) ;No wrapping, only bitseg needed returns a binary of floats of size 64 of floats which are larger than 10.0 from the binary b1 and of size 32. The returned numbers are first printed. N.B. A word of warning when using guards when extracting elements from a binary. When a match/guard fails for a binary no more attempts will be made to extract data from the binary. This means that even if a value could be extracted from the binary if the guard fails this value will be lost and extraction will cease. This is *NOT* the same as having following boolean test which may remove an element but will not stop extraction. Using a guard is probably not what you want! Normal vanilla Erlang does the same thing but does not allow guards. ETS and Mnesia -------------- Apart from (emp-record ...) macros for ETS Match Patterns, which are also valid in Mnesia, LFE also supports match specifications and Query List Comprehensions. The syntax for a match specification is the same as for match-lambdas: (match-spec ((arg ... ) \{\{(when e ...)\}\} ...) - Matches clauses ... ) For example: (: ets select db (match-spec ([(tuple _ a b)] (when (> a 3)) (tuple 'ok b)))) It is a macro which creates the match specification structure which is used in ets:select and mnesia:select. The same match-spec macro can also be used with the dbg module. The same restrictions as to what can be done apply as for vanilla match specifications: - There is only a limited number of BIFs which are allowed - There are some special functions only for use with dbg - For ets/mnesia it takes a single parameter which must a tuple or a variable - For dbg it takes a single parameter which must a list or a variable N.B. the current macro neither knows nor cares whether it is being used in ets/mnesia or in dbg. It is up to the user to get this right. Macros, especially record macros, can freely be used inside match specs. *CAVEAT* Some things which are known not to work in the current version are andalso, orelse and record updates. Query List Comprehensions ------------------------- LFE supports QLCs for mnesia through the qlc macro. It has the same structure as a list comprehension and generates a Query Handle in the same way as with qlc:q([...]). The handle can be used together with all the combination functions in the module qlc. For example: (qlc (lc ((<- (tuple k v) (: ets table e2)) (== k i)) v) \{\{Option\}\}) Macros, especially record macros, can freely be used inside query list comprehensions. *CAVEAT* Some things which are known not to work in the current version are nested QLCs and let/case/recieve which shadow variables. Predefined LFE functions ------------------------ The following more or less standard lisp functions are pre-defined: (<arith_op> expr ...) (<comp_op> expr ...) The standard arithmentic operators, + - * /, and comparison operators, > >= < =< == /= =:= =/= , can take multiple arguments the same as their standard lisp counterparts. This is still experimental and implemented using macros. They do, however, behave like normal functions and evaluate ALL their arguments before doing the arithmetic/comparisons operations. (acons key value list) (assoc key list) (rassoc value list) The standard association list functions. (subst new old tree) (subst-if new test tree) (subst-if-not new test tree) The standard substituition functions. (macroexpand-1 expr \{\{environment\}\}) If Expr is a macro call, does one round of expansion, otherwise returns Expr. (macroexpand expr \{\{environment\}\}) Returns the expansion returned by calling macroexpand-1 repeatedly, starting with Expr, until the result is no longer a macro call. (macroexpand-all expr \{\{environment\}\}) Returns the expansion from the expression where all macro calls have been expanded with macroexpand. NOTE that when no explicit environment is given the macroexpand functions then only the default built-in macros will be expanded. Inside macros and in the shell the variable $ENV is bound to the current macro environment. (eval expr \{\{environment\}\}) Evaluate the expression expr. Note that only the pre-defined lisp functions, erlang BIFs and exported functions can be called. Also no local variables can be accessed. To access local variables the expr to be evaluated can be wrapped in a let defining these. For example if the data we wish to evaluate is in the variable expr and it assumes there is a local variable "foo" which it needs to access then we could evaluate it by calling: (eval `(let ((foo ,foo)) ,expr)) Notes ----- NYI - Not Yet Implemented N.B. - Nota bene (note well)