LFE (programming language)

Last updated
LFE
LFE (Lisp Flavored Erlang) Logo.png
Paradigm Multi-paradigm: concurrent, functional
Family Erlang, Lisp
Designed by Robert Virding
Developer Robert Virding
First appeared2008;17 years ago (2008)
Stable release
2.1.1 / 6 January 2023;2 years ago (2023-01-06)
Typing discipline dynamic, strong
Implementation language Erlang
OS Cross-platform
License Apache 2.0
Filename extensions .lfe .hrl
Website lfe.io
Influenced by
Erlang, Common Lisp, Maclisp, Scheme, Elixir, Clojure, Hy
Influenced
Joxa, Concurrent Schemer

Lisp Flavored Erlang (LFE) is a functional, concurrent, garbage collected, general-purpose programming language and Lisp dialect built on Core Erlang and the Erlang virtual machine (BEAM). LFE builds on Erlang to provide a Lisp syntax for writing distributed, fault-tolerant, soft real-time, non-stop applications. LFE also extends Erlang to support metaprogramming with Lisp macros and an improved developer experience with a feature-rich read–eval–print loop (REPL). [1] LFE is actively supported on all recent releases of Erlang; the oldest version of Erlang supported is R14.

Contents

History

Robert Virding Robert Virding, 2013.jpg
Robert Virding

Initial release

Initial work on LFE began in 2007, when Robert Virding started creating a prototype of Lisp running on Erlang. [2] This work was focused primarily on parsing and exploring what an implementation might look like. No version control system was being used at the time, so tracking exact initial dates is somewhat problematic. [2]

Virding announced the first release of LFE on the Erlang Questions mail list in March 2008. [3] This release of LFE was very limited: it did not handle recursive letrecs, binarys, receive, or try; it also did not support a Lisp shell. [4]

Initial development of LFE was done with version R12B-0 of Erlang [5] on a Dell XPS laptop. [4]

19581960196519701975198019851990199520002005201020152020
 LISP 1, 1.5, LISP 2(abandoned)
  Maclisp
  Interlisp
  MDL
  Lisp Machine Lisp
  Scheme  R5RS R6RS R7RS small
  NIL
  ZIL (Zork Implementation Language)
  Franz Lisp
  muLisp
  Common Lisp  ANSI standard
  Le Lisp
  MIT Scheme
  XLISP
  T
  Chez Scheme
  Emacs Lisp
  AutoLISP
  PicoLisp
  Gambit
  EuLisp
  ISLISP
  OpenLisp
  PLT Scheme   Racket
  newLISP
  GNU Guile
  Visual LISP
  Clojure
  Arc
  LFE
  Hy

Motives

Robert Virding has stated that there were several reasons why he started the LFE programming language: [2]

Features

Syntax and semantics

Symbolic expressions (S-expressions)

Like Lisp, LFE is an expression-oriented language. Unlike non-homoiconic programming languages, Lisps make no or little syntactic distinction between expressions and statements : all code and data are written as expressions. LFE brought homoiconicity to the Erlang VM.

Lists

In LFE, the list data type is written with its elements separated by whitespace, and surrounded by parentheses. For example, (list12'foo) is a list whose elements are the integers 1 and 2, and the atom [[foo|foo]]. These values are implicitly typed: they are respectively two integers and a Lisp-specific data type called a symbolic atom, and need not be declared as such.

As seen in the example above, LFE expressions are written as lists, using prefix notation. The first element in the list is the name of a form, i.e., a function, operator, or macro. The remainder of the list are the arguments.

Operators

The LFE-Erlang operators are used in the same way. The expression

(*(+123456)2)

evaluates to 42. Unlike functions in Erlang and LFE, arithmetic operators in Lisp are variadic (or n-ary), able to take any number of arguments.

Lambda expressions and function definition

LFE has lambda, just like Common Lisp. It also, however, has lambda-match to account for Erlang's pattern-matching abilities in anonymous function calls.

Erlang idioms in LFE

This section does not represent a complete comparison between Erlang and LFE, but should give a taste.

Pattern matching

Erlang:

1>{Len,Status,Msg}={8,ok,"Trillian"}.{8,ok,"Trillian"}2>Msg."Trillian"

LFE:

lfe>(set(tuplelenstatusmsg)#(8ok"Trillian"))lfe>;; or with LFE literal tuple syntax:lfe>(set`#(,len,status,msg)#(8ok"Trillian"))#(8ok"Trillian")lfe>msg"Trillian"

List comprehensions

Erlang:

1>[trunc(math:pow(3,X))||X<-[0,1,2,3]].[1,3,9,27]

LFE:

lfe>(list-comp((<-x'(0123)))(trunc(math:pow3x)))(13927)

Or idiomatic functional style:

lfe>(lists:map(lambda(x)(trunc(math:pow3x)))'(0123))(13927)

Guards

Erlang:

right_number(X)whenX==42;X==276709->true;right_number(_)->false.

LFE:

(defunright-number?((x)(when(orelse(==x42)(==x276709)))'true)((_)'false))

cons'ing in function heads

Erlang:

sum(L)->sum(L,0).sum([],Total)->Total;sum([H|T],Total)->sum(T,H+Total).

LFE:

(defunsum(l)(suml0))(defunsum(('()total)total)(((consht)total)(sumt(+htotal))))

or using a ``cons`` literal instead of the constructor form:

(defunsum(l)(suml0))(defunsum(('()total)total)((`(,h.,t)total)(sumt(+htotal))))

Matching records in function heads

Erlang:

handle_info(ping,#state{remote_pid=undefined}=State)->gen_server:cast(self(),ping),{noreply,State};handle_info(ping,State)->{noreply,State};

LFE:

(defunhandle_info(('ping(=(match-stateremote-pid'undefined)state))(gen_server:cast(self)'ping)`#(noreply,state))(('pingstate)`#(noreply,state)))

Receiving messages

Erlang:

universal_server()->receive{become,Func}->Func()end.

LFE:

(defununiversal-server()(receive((tuple'becomefunc)(funcallfunc))))

or:

(defununiversal-server()(receive(`#(become,func)(funcallfunc))))

Examples

Erlang interoperability

Calls to Erlang functions take the form (<module>:<function> <arg1> ... <argn>):

(io:format"Hello, World!")

Functional paradigm

Using recursion to define the Ackermann function:

(defunackermann((0n)(+n1))((m0)(ackermann(-m1)1))((mn)(ackermann(-m1)(ackermannm(-n1)))))

Composing functions:

(defuncompose(fg)(lambda(x)(funcallf(funcallgx))))(defuncheck()(let*((sin-asin(compose#'sin/1#'asin/1))(expected(sin(asin0.5)))(compose-result(funcallsin-asin0.5)))(io:format"Expected answer: ~p~n"(listexpected))(io:format"Answer with compose: ~p~n"(listcompose-result))))

Concurrency

Message-passing with Erlang's light-weight "processes":

(defmodulemessenger-back(export(print-result0)(send-message2)))(defunprint-result()(receive((tuplepidmsg)(io:format"Received message: '~s'~n"(listmsg))(io:format"Sending message to process ~p ...~n"(listpid))(!pid(tuplemsg))(print-result))))(defunsend-message(calling-pidmsg)(let((spawned-pid(spawn'messenger-back'print-result())))(!spawned-pid(tuplecalling-pidmsg))))

Multiple simultaneous HTTP requests:

(defunparse-args(flag)"Given one or more command-line arguments, extract the passed values.  For example, if the following was passed via the command line:    $ erl -my-flag my-value-1 -my-flag my-value-2  One could then extract it in an LFE program by calling this function:    (let ((args (parse-args 'my-flag)))      ...      )  In this example, the value assigned to the arg variable would be a list  containing the values my-value-1 and my-value-2."(let((`#(ok,data)(init:get_argumentflag)))(lists:mergedata)))(defunget-pages()"With no argument, assume 'url parameter was passed via command line."(let((urls(parse-args'url)))(get-pagesurls)))(defunget-pages(urls)"Start inets and make (potentially many) HTTP requests."(inets:start)(plists:map(lambda(x)(get-pagex))urls))(defunget-page(url)"Make a single HTTP request."(let*((method'get)(headers'())(request-data`#(,url,headers))(http-options())(request-options'(#(syncfalse))))(httpc:requestmethodrequest-datahttp-optionsrequest-options)(receive(`#(http#(,request-id#(error,reason)))(io:format"Error: ~p~n"`(,reason)))(`#(http#(,request-id,result))(io:format"Result: ~p~n"`(,result))))))

References

  1. Virding, Robert. "Lisp Flavored Erlang" (PDF). Erlang Factory. Retrieved 2014-01-17.
  2. 1 2 3 "LFE History on the Lisp Flavored Erlang mail list" . Retrieved 2014-05-28.
  3. "LFE announcement on Erlang Questions mail list" . Retrieved 2014-01-17.
  4. 1 2 Armstrong, Joe; Virding, Robert (2013-12-30). "Hardware used in the development of Erlang and LFE" (Email exchange). Interviewed by Duncan McGreggor. Retrieved 2014-01-17.
  5. "Follow-up to LFE announcement on Erlang Questions mail list" . Retrieved 2014-01-17.