![]() |
![]()
| ![]() |
![]()
NAMElfe_guide - Lisp Flavoured Erlang User Guide SYNOPSISNote: {{ ... }} is used to denote optional syntax. LITERALS AND SPECIAL SYNTACTIC RULESIntegersIntegers can be written in various forms and number bases:
In all these forms, the case of the indicating letter is not significant, i.e. #b1010 and #B1010 are identical as are #16rf00 and #16Rf00. Similarly, the case is not significant for digits beyond 9 (i.e. `a', `b', `c', ... for number bases larger than 10), e.g. #xabcd is the same as #xABCD and can even be mixed in the same number, e.g. #36rHelloWorld is valid and the same number as #36Rhelloworld and #36rHELLOWORLD. The character notation using hexadecimal code representation (#\x....;) is basically the same thing as the regular hexadecimal notation #x... except that it conveys to the reader that a character is intended and that it does a sanity check on the value (e.g. negative numbers and value outside the Unicode range are not permitted). Floating point numbersThere is only one type of floating point numbers and the literals are written in the usual way, e.g. these are all valid floating point numbers:
The one thing to watch out for is that you cannot omit the part before or after the decimal point if it is zero. E.g. the following are not valid forms: 100. or .125. StringsThere are two forms of strings: list strings and binary strings. List StringsList strings are just lists of integers (where the values have to be from a certain set of numbers that are considered valid characters) but they have their own syntax for literals (which will also be used for integer lists as an output representation if the list contents looks like it is meant to be a string): “any text between double quotes where " and other special characters like \n can be escaped”. As a special case you can also write out the character number in the form \xHHH; (where “HHH” is an integer in hexadecimal notation), e.g. "\x61;\x62;\x63;" is a complicated way of writing "abc". This can be convenient when writing Unicode letters not easily typeable or viewable with regular fonts. E.g. "Cat: \\x1f639;" might be easier to type (and view on output devices without a Unicode font) then typing the actual Unicode letter. Binary StringsBinary strings are just like list strings but they are represented differently in the virtual machine. The simple syntax is #"...", e.g. #"This is a binary string \n with some \"escaped\" and quoted (\\x1f639;) characters" You can also use the general format for creating binaries (#B(...), described below), e.g. #B("a"), #"a", and #B(97) are all the same binary string. Character EscapingCertain control characters can be more readably included by using their escaped name:
Alternatively you can also use the hexadecimal character encoding, e.g. "a\nb" and "a\x0a;b" are the same string. Triple-quoted StringsLFE’s triple-quote strings are modelled on those in Erlang so we will use their description of them. Strings, both list strings and binary strings, can also be written as triple-quoted strings, which can be indented over multiple lines to follow the indentation of the surrounding code. They are also verbatim, that is, they do not allow escape sequences, and thereby do not need double quote characters to be escaped. Example, with verbatim double quote characters:
That is equivalent to the normal single quoted string (which also allows newlines):
The opening and the closing lines have the delimiters: the ““” characters. The lines between them are the content lines. The newline on the opening line is not regarded as string content, nor is the newline on the last content line. The indentation is defined by the white space character sequence preceding the delimiter on the closing line. That character sequence is stripped from all content lines. There can only be white space before the delimiter on the closing line, or else it is regarded as a content line. The opening line is not allowed to have any characters other than white space after the delimiter, and all content lines must start with the defined indentation character sequence, otherwise the string has a syntax error. Here is a larger example:
That corresponds to the normal string:
Binary strings can also be written as triple-quoted strings:
which correspnds to the binary:
Function ReferencesThe function references are the forms:
These forms evaluate to function references which can be used with funcall to call the functions. There is also a special syntax:
which is still supported but is deprecated. BinariesWe have already seen binary strings, but the #B(...) syntax can be used to create binaries with any contents. Unless the contents is a simple integer you need to annotate it with a type and/or size. Example invocations are that show the various annotations:
Learn more about “segments” of binary data e.g. in “Learn You Some Erlang” http://learnyousomeerlang.com/starting-out-for-real#bit-syntax. ListsLists are formed either as ( ... ) or [ ... ] where the optional elements of the list are separated by some form or whitespace. For example:
TuplesTuples are written as #(value1 value2 ...). The empty tuple #() is also valid. MapsMaps are written as #M(key1 value1 key2 value2 ...) The empty map is also valid and written as #M(). StructsStructs are written as #S(struct-name key1 value1 key2 value2 ...). Note that structs cannot be created with the literal syntax, the (struct mod-name ...) form must be used. SymbolsThings that cannot be parsed as any of the above are usually considered as a symbol. Simple examples are foo, Foo, foo-bar, :foo. But also somewhat surprisingly 123foo and 1.23e4extra (but note that illegal digits don’t make a number a symbol when using the explicit number base notation, e.g. #b10foo gives an error). Symbol names can contain a surprising breadth or characters, basically all of the latin-1 character set without control character, whitespace, the various brackets, double quotes and semicolon. Of these, only |, \', ', ,, and # may not be the first character of the symbol’s name (but they are allowed as subsequent letters). I.e. these are all legal symbols: foo, foo, µ#, ±1, 451°F. Symbols can be explicitly constructed by wrapping their name in vertical bars, e.g. |foo|, |symbol name with spaces|. In this case the name can contain any character of in the range from 0 to 255 (or even none, i.e. || is a valid symbol). The vertical bar in the symbol name needs to be escaped: |symbol with a vertical bar \| in its name| (similarly you will obviously have to escape the escape character as well). CommentsComments come in two forms: line comments and block comments. Line comments start with a semicolon (;) and finish with the end of the line. Block comments are written as #| comment text |# where the comment text may span multiple lines but my not contain another block comment, i.e. it may not contain the character sequence #|. Evaluation While Reading#.(... some expression ...). E.g. #.(+ 1 1) will evaluate the (+ 1 1) while it reads the expression and then be effectively 2. Supported formsCore forms
Basic macro forms
Common Lisp inspired macros
PatternsWritten as normal data expressions where symbols are variables and use quote to match explicit values. Binaries and tuples have special syntax.
Repeated variables are supported in patterns and there is an automatic comparison of values. _ 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. GuardsWherever a pattern occurs (in 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:
An empty guard, (when), always succeeds as there is no test which fails. This simplifies writing macros which handle guards. Comments in Function DefinitionsInside functions defined with defun LFE permits optional comment strings in the Common Lisp style after the argument list. So we can have:
Optional comments are also allowed in match style functions after the function name and before the clauses:
This is also possible in a similar style in local functions defined by flet and fletrec:
Variable Binding and ScopingVariables are lexically scoped and bound by lambda, match-lambda and let forms. All variables which are bound within these forms shadow variables bound outside but other variables occurring in the bodies of these forms will be imported from the surrounding environments.No variables are exported out of the form. So for example the following function:
The variable y in the call (zip y) comes from the function arguments. However, the x bound in the let will shadow the x from the arguments so in the call (zap x z) the x is bound in the let while the z comes from the function arguments. In the final (zop x y) both x and y come from the function arguments as the let does not export x. Function Binding and ScopingFunctions are lexically scoped and bound by the top-level defun and by the macros flet and fletrec. LFE is a Lisp-2 so functions and variables have separate namespaces and when searching for function both name and arity are used. This means that when calling a function which has been bound to a variable using (funcall func-var arg ...) is required to call lambda/match-lambda bound to a variable or used as a value. Unqualified functions shadow as stated above which results in the following order within a module, outermost to innermost:
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 predefined 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. The compiler will warn when core forms are redefined but it is not an error. Module definitionThe basic forms for defining a module and extending its metadata and attributes are:
The valid meta data is (type typedef ...), (opaque typedef ...), (spec function-spec ...) and (record record-def ...). Each can take multiple definitions in one meta form. Attributes declarations have the syntax (attribute value-1 ...) where the attribute value is a list off the values in the declaration To simplify defining modules there is a predefined macro:
We can have multiple export and import attributes within module declaration. The (export all) attribute is allowed together with other export attributes and overrides them. Other attributes which are not recognized by the compiler are allowed and are simply passed on to the module and can be accessed with the module_info/0-1 functions. In the import attribute the (from mod (f1 2) ...) means that the call (f1 'everything 42) will be converted by the compiler to (mod:f1 'everything 42)) while the (rename mod ((g2 2) m-g1) ...) means that the call (m-g1 'everything 42) will be converted to (mod:g1 'everything 42). The rename form can be used as compact way of indicating the imported function’s module. Note that when importing a module
In the module-alias attribute the (really-long-module-name rlmn) declaration means that the call (lrmn:foo 'everything 42) will be converted by the compiler to (really-long-module-name:foo 'everything 42). This is often used to write short module names in the code when calling functions in modules with long names. It is in many ways better than using import as it does not hide that we are calling a function in another module. MacrosMacro 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 arguments 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:
Macros are definitely NOT hygienic in any form. However, variable scoping and variable immutability remove most of the things that can cause unhygienic macros. It can be done but you are not going to do it by mistake. The only real issue is if you happen to be using a variable which has the same name as one which the macro generates, that can cause problems. The work around for this is to give variables created in the macro expansion really weird names like | - foo - | which no one in their right mind would use. To simplify writing macros there are a number of predefined macros:
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:
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:
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. The are implemented the the module scm and are supported with scm:define-syntax and scm:let-syntax and the equivalent scm:defsyntax and scm: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:
There is an include file “include/scm.lfe” which defines macros so the names don’t have to be prefixed with scm:. CAVEAT While it is perfectly legal to define a Core form as a macro these will silently be ignored by the compiler. Comments in Macro DefinitionsInside macros defined with defmacro LFE permits optional comment strings in the Common Lisp style after the argument list. So we can have:
Optional comments are also allowed in match style macros after the macro name and before the clauses:
This is also possible in a similar style in local functions defined by macrolet:
RecordsRecords 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 the atom `undefined'. The basic forms for defining a record, creating, accessing and updating it are:
Note that the list of field/value pairs when making or updating a record is a flat list. Note that the old make-record form has been deprecated and is replaced by record which better matches other constructors like tuple and map. It still exists but should not be used. We will explain these forms with a simple example. To define a record we do:
which defines a record person with the fields name (default value ""), address (default value "" and type (string)) and age. To make an instance of a person record we do:
The record form is also used to define a pattern. We can get the value of the address field in a person record and set it by doing (the variable robert references a person record):
Note that we must include the name of the record when accessing it and there is no need to quote the record and field names as these are always literal atoms. To simplify defining and using records there is a predefined macro:
This will create access macros for record creation and accessing and updating fields. The make-, match- and update- forms takes optional argument pairs field-name value to get non-default values. E.g. for
the following will be generated:
Note that the older now deprecated set- forms are still generated. StructsStructs in LFE are the same as Elixir structs and have been defined in the same way so to be truly compatible. This means that you can use structs defined in Elixr from LFE and structs defined in LFE from Elixir.
We will explain these forms with a simple example. To define a struct we do:
which defines a struct with the name of the current module with the fields name (default value ""), address (default value "" and type (string)) and age. To make an instance of struct we do:
The struct form is also used to define a pattern. We can get the value of the address field in the struct and set it by doing (the variable robert references a struct):
Note that a struct automatically gets the name of the module in which it is defined so that there can only be one struct defined in a module. This mirrors how structs are implemented in Elixir. Note that we must include the name of the struct when accessing it and there is no need to quote the struct and field names as these are always literal atoms. Binaries/bitstringsA binary is
where seg is
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. MapsA map is created with:
To access maps there are the following forms:
There are also alternate short forms msiz, mref, mset, mupd and mrem based on the Maclisp array reference forms. They take the same arguments as their longer alternatives. Core formsIfThe LFE if is more like a classic if than the Erlang if. For the test it allows any Erlang boolean expression which must return either true or false. The false expression is optional and if it not included the if returns false. Some examples:
CondThe LFE cond is similar to if and tests in cond are Erlang tests in that they should return either true or false. If no test succeeds then the cond does not generate an exception but just returns false. There is a simple catch-all “test” else which must last and can be used to handle the case when all tests fail. Cond has been extended with the extra test (?= pat expr) which tests if the result of expr matches the pattern pat. If so it binds the variables in pat which can be used in the cond test body expression. A optional guard is allowed here. An example:
MaybeLFE has an Erlang compatible maybe. It has the same features as the Erlang maybe with the ?= operator and else. The expressions in the maybe block are evaluated sequentially:
If all the expressions succeed then maybe block returns the value of expr-n. The conditional match
can short circuit this. If the match succeeds then the variables in pattern become bound. The ?= match returns the value of the expressions. If the match fails then the rest of the expressions in the maybe block are skipped and maybe returns the value of the expr. The maybe block can be augmented with else clauses:
If a conditional match fails then the value of the expression is matched against the patterns in the else claueses and if one matches then its body is evaluated. Guard tests are allowed. If no pattern matches then an else-clause run-time error occurs. An example:
The maybe body can include ?= forms which behave in the same way as in the Erlang maybe. As LFE cannot bind variables in the same way as in Erlang we allow let in the body to bind variables. These variables are only local in the let body so this body is “lifted” upto the top level maybe body and so can contain ?= forms as well. List/binary comprehensionsList/binary comprehensions are supported as macros. The syntax for list comprehensions is:
where the last expr is used to generate the elements of the list. The syntax for binary comprehensions is:
where the final expr is a bitstring expression and is used to generate the elements of the binary. The supported qualifiers, in both list/binary comprehensions are:
Some examples:
returns a list of all the even elements of the list l1 which are greater than 5.
returns a binary of floats of size 64 bits which are from the binary b1 where they are of size 32 bits and larger than 10.0. The returned numbers are first printed. This could also be written using a guard for the test:
ETS and MnesiaLFE also supports match specifications and Query List Comprehensions. The syntax for a match specification is the same as for match-lambdas:
For example:
It is a macro which creates the match specification structure which is used in ets:select and mnesia:select. For tracing instead of the ets-ms macro there is the trace-ms macro which is also used in conjunction with the dbg module. The same restrictions as to what can be done apply as for vanilla match specifications:
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 ComprehensionsLFE 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:
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 functionsThe following more or less standard lisp functions are predefined:
The standard arithmetic 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.
The standard association list functions.
The standard substitution functions.
If Expr is a macro call, does one round of expansion, otherwise returns Expr.
Returns the expansion returned by calling macroexpand-1 repeatedly, starting with Expr, until the result is no longer a macro call.
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.
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:
Supplemental Common Lisp FunctionsLFE provides the module cl which contains the following functions which closely mirror functions defined in the Common Lisp Hyperspec. Note that the following functions use zero-based indices, like Common Lisp (unlike Erlang, which start at index `1'). A major difference between the LFE versions and the Common Lisp versions of these functions is that the boolean values are the LFE 'true and 'false. Otherwise the definitions closely follow the CL definitions and won’t be documented here.
Furthermore, there is an include file which developers may which to utilize in their LFE programs: (include-lib "lfe/include/cl.lfe"). Currently this offers Common Lisp predicates, but may include other useful macros and functions in the future. The provided predicate macros wrap the various is_* Erlang functions; since these are expanded at compile time, they are usable in guards. The include the following:
Non-predicate macros in lfe/include/cl.lfe include:
Supplemental Clojure FunctionsFrom LFE’s earliest days, it’s Lisp-cousin Clojure (created around the same time) has inspired LFE developers to create similar, BEAM-versions of those functions. These were collected in a separate library and then expanded upon, until eventually becoming part of the LFE standard library. Function definition macros:
Threading macros:
Conditional macros:
Predicate macros:
Other:
Most of the above mentioned macros are available in the clj include file, the use of which allows developers to forego the clj: prefix in calls:
Notes
SEE ALSOlfe(1), lfescript(1), lfe_cl(3) AUTHORSRobert Virding.
|