Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Relationship to Erlang and Other Lisps

Relationship to Erlang

LFE is not:

  • A syntax overlay (it has different semantics via macros)
  • An FFI to Erlang (there is no foreign function interface)
  • A separate runtime (it is the BEAM VM)
  • An Erlang dialect (it's a different language that compiles to same target)

LFE is:

  • Semantically equivalent at the bytecode level
  • Perfectly interoperable with zero overhead
  • OTP-native (all behaviors, supervision, applications work)
  • Tool-compatible (Dialyzer, Observer, Debugger, etc. work seamlessly)

Code equivalence example:

;; LFE
(defun factorial (n)
  (factorial n 1))

(defun factorial (0 acc) acc)
(defun factorial (n acc) (when (> n 0))
  (factorial (- n 1) (* n acc)))
%% Equivalent Erlang
factorial(N) -> factorial(N, 1).

factorial(0, Acc) -> Acc;
factorial(N, Acc) when N > 0 ->
    factorial(N - 1, N * Acc).

Both compile to identical BEAM bytecode.

Relationship to Common Lisp

LFE borrows from Common Lisp:

  • Lisp-2 namespace separation (functions and variables distinct)
  • Macro style (lambda-based, not pattern-based)
  • Quote/backquote/comma syntax
  • Many function names (car, cdr, mapcar, etc.)

LFE differs from Common Lisp:

  • No CLOS (use Erlang records/behaviors instead)
  • No condition system (use Erlang try/catch/exit)
  • No mutable data structures (Erlang immutability)
  • Pattern matching is primary (vs. destructuring-bind)
  • Processes instead of threads
  • Message passing instead of shared state

Compatibility: The cl module provides 60+ CL functions with correct semantics (including () = false).

Relationship to Clojure

LFE borrows from Clojure:

  • Threading macros (->, ->>, as->, some->, etc.)
  • Conditional macros (if-let, when-let, condp)
  • Rich set of predicates
  • Lazy sequence concepts
  • Functional composition style

LFE differs from Clojure:

  • No persistent data structures (Erlang uses copying immutability)
  • No STM (Erlang uses actors/message passing)
  • Pattern matching is primary (vs. destructuring)
  • Lisp-2 (Clojure is Lisp-1)
  • S-expressions (Clojure has reader macros for vectors/maps)

Compatibility: The clj module provides threading macros and predicates with Clojure-like semantics.

Relationship to Scheme

LFE borrows from Scheme:

  • Syntax-rules (macro-by-example system)
  • Hygienic macro concepts
  • Simple, elegant core
  • Lexical scoping only

LFE differs from Scheme:

  • Lisp-2 (Scheme is Lisp-1)
  • Eager evaluation (Scheme encourages laziness)
  • Pattern matching pervasive
  • No continuations (Erlang has processes instead)
  • Macro expansion is explicit, not automatic hygiene

Compatibility: The scm module provides full syntax-rules implementation with ellipsis support.

Unique Position in Language Ecosystem

LFE occupies a unique niche:

Lisp Family          BEAM VM Family
    │                      │
    │                      │
    ├─ Common Lisp         ├─ Erlang
    ├─ Scheme              ├─ Elixir
    ├─ Clojure (JVM)       │
    │                      │
    └─────────┬────────────┘
              │
              └─ LFE (intersection)
                 - Lisp syntax & macros
                 - BEAM semantics & concurrency
                 - Three-dialect compatibility
                 - Zero-overhead interop

No other language provides:

  • Lisp metaprogramming on BEAM VM
  • Pattern matching as primary paradigm in Lisp
  • Actor model concurrency in Lisp
  • OTP supervision/behaviors in Lisp
  • Erlang tool compatibility in Lisp