
ExLisp: A Lisp implementation running on Elixir / BEAM
A Lisp implementation running on Elixir / BEAM.
以下正文同步自 Hacker News 最新,版权归原站所有,已转换为易读排版。
A Lisp implementation running on Elixir / BEAM.
Install from Hex.pm
You can install it globally from Hex.pm.
mix escript.install hex exlisp
Note: After installation, add ~/.mix/escripts to your PATH to run the exlisp command directly.
exlisp
Build from Source
mix escript.build ./exlisp
REPL
When started, it enters the REPL interface and evaluates expressions as soon as top-level parentheses are closed (supports multi-line input).
exlisp(1)> (+ 1 2) 3 exlisp(2)> (+ (* 2 3) (- 10 4)) 12 exlisp(3)> (:math:sqrt 16) 4.0 exlisp(4)> (:math:pow 2 8) 256.0 exlisp(5)> (cons 1 [2 3]) [1, 2, 3] exlisp(6)> (:lists:reverse [1 2 3 4]) [4, 3, 2, 1] exlisp(7)> (:lists:sum [10 20 30]) 60 exlisp(8)> (:math:sqrt (+ (:math:pow 3 2) (:math:pow 4 2))) 5.0 exlisp(9)> :io:read ">> "
42. {:ok, 42} exlisp(10)> IO.puts "hello" hello :ok exlisp(11)> (String.upcase "hello") "HELLO" exlisp(12)> (Enum.count [1 2 3 4 5]) 5
Re-running Expressions and Referencing Results in REPL
You can specify the prompt number n to re-execute past expressions or reference evaluation results.
!n: Re-execute the n-th expression (e.g. !1)
!-1: Re-execute the previous expression
(r n): Re-execute the n-th expression as a Lisp expression (without args (r) for previous)
exlisp(1)> (+ 10 20) 30 exlisp(2)> !1 30 exlisp(3)> (r 1) 30
- Referencing Evaluation Results and Input Expressions
(v n): Get the n-th evaluation result (without args (v) for previous)
*, **, ***: Previous / 2nd previous / 3rd previous evaluation results (Common Lisp standard variables)
+, ++, +++: Previous / 2nd previous / 3rd previous input expressions
exlisp(1)> (+ 1 2) 3 exlisp(2)> (+ * 10) 13 exlisp(3)> (v 1) 3 exlisp(4)> [*** ** *] [3, 13, 3]
Examples
Basic Arithmetic and Built-in Functions
Built-in functions such as arithmetic operations and cons are available.
;; Arithmetic operations (+ 1 2) ; => 3 (* 2 3 4) ; => 24
;; Constructing lists (cons) (cons 1 [2 3]) ; => [1, 2, 3] (cons 1 []) ; => [1] (cons (+ 1 2) [(* 2 2)]) ; => [3, 4]
Calling Erlang Functions
You can call Erlang standard module functions in the format :module:function or module:function.
;; Math functions (:math:sqrt 16) ; => 4.0 (:math:pow 2 8) ; => 256.0
;; List operations (:lists:reverse [1 2 3 4]) ; => [4, 3, 2, 1] (:lists:sum [10 20 30]) ; => 60 (:lists:nth 2 [10 20 30]) ; => 20
;; System and date information (:erlang:date) ; => {2026, 9, 4} (:os:type) ; => {:unix, :linux}
Nested Execution and Combining Return Values
Return values of functions can be directly combined into other calculations or function calls.
;; Passing function results to arithmetic operations (+ 10 (:math:sqrt 25)) ; => 15.0
;; Combining multiple function results (Pythagorean theorem: 3^2 + 4^2 = 5^2) (:math:sqrt (+ (:math:pow 3 2) (:math:pow 4 2))) ; => 5.0
;; Fetching elements from list and calculating (* (:lists:nth 2 [10 20 30]) 2) ; => 40
Calling Elixir Functions
You can also call Elixir module functions using the ModuleName.function_name format.
(String.upcase "hello") ; => "HELLO" (Enum.count [1 2 3 4 5]) ; => 5 (IO.puts "hello") ; => :ok
At the top level, you can also execute calls without outer parentheses:
String.upcase "hello" ; => "HELLO" :math:sqrt 16 ; => 4.0
Elixir Interoperability (API)
You can evaluate Lisp expressions, get/set global variables, and invoke Lisp functions directly from Elixir code.
Evaluate Lisp expressions
ExLisp.eval("(defparameter count 100)")
=> :count
Get variable
ExLisp.get_var(:count)
=> 100
Set variable
ExLisp.set_var(:count, 200) ExLisp.eval("count")
=> 200
Define Lisp function and call it from Elixir
ExLisp.eval("(defun multiply (a b) (* a b))")
ExLisp.call(:multiply, [6, 7])
=> 42
Get as an Elixir anonymous function and execute
mult = ExLisp.get_fun(:multiply) mult.(3, 5)
=> 15
Using Quicklisp Libraries (ql:quickload)
ExLisp supports Quicklisp and ASDF, allowing you to automatically download and load libraries written in Pure Common Lisp (without C extensions or FFI/CFFI).
;; Load and use Alexandria exlisp(1)> (ql:quickload :alexandria) (ALEXANDRIA) exlisp(2)> (clamp 15 0 10) 10 exlisp(3)> (clamp -5 0 10) 0
;; Load and use split-sequence exlisp(4)> (ql:quickload :split-sequence) (SPLIT-SEQUENCE) exlisp(5)> (split-sequence #\Space "hello world foo bar") ("hello" "world" "foo" "bar")
Using Hex.pm Libraries
Supports single packages (with or without version requirements) or lists of multiple packages.
;; Install and use Jason exlisp(1)> (hex:install :jason "~> 1.4") (Jason) exlisp(2)> (Jason.encode! [1 2 3]) "[1,2,3]"
;; Install latest version (omitting version requirement) exlisp(3)> (hex:install :floki) (Floki) exlisp(4)> (Floki.parse_document! "<h1>Hello</h1>") ({"h1", NIL, ("Hello")})
;; Batch install multiple packages exlisp(5)> (hex:install '((:decimal "~> 2.0") :timex)) (Decimal Timex) exlisp(6)> (Decimal.new "123.45") #Decimal<123.45>
Running Lisp Files and BEAM Compilation
Supports script execution (passing a file argument or --script), interactive REPL startup with preloaded files (--load), and compiling to BEAM bytecode (-c / --compile).
Evaluates and executes the file sequentially as a script from top to bottom, then exits the process upon completion (no banner display, does not enter REPL).
Pass file argument directly
exlisp script.lisp
Or use --script option
exlisp --script script.lisp exlisp -s script.lisp
- Loading Files and Starting REPL (--load, -l)
Loads and runs a file, then starts the interactive REPL with the loaded environment preserved.
--load option
exlisp --load file.lisp exlisp -l file.lisp
- Compiling to BEAM Bytecode and Persistence (-c, --compile)
By compiling Lisp source files (.lisp) to BEAM bytecode (.beam files), compiled variables and functions can be directly accessed from other processes such as iex -S mix even after the exlisp command exits.
;; sample.lisp (defparameter base 100) (defvar multiplier 2)
(defun add (a b) (+ a b))
(defun calc (x) (* (+ x base) multiplier))
Compiling to BEAM with exlisp -c
Specifying the -c (or --compile) option compiles the Lisp file into BEAM bytecode.
If -m or -o is not specified, the defaults are:
When -m and -o are omitted (default)
exlisp -c sample.lisp
=> Compiled sample.lisp to _build/dev/lib/exlisp/ebin/Elixir.ExLisp.Global.beam (module: ExLisp.Global)
Options can be specified to customize output:
If -m is omitted, it is defined as the ExLisp.Global module, callable via ExLisp.Global.<function_name> (function names are lowercased).
Under a Mix environment, the compile path is automatically set, so you can call it directly:
$ iex -S mix
Call compiled module functions directly
iex> ExLisp.Global.add(10, 20) 30
iex> ExLisp.Global.calc(5) 210
Access via ExLisp API
iex> ExLisp.get_var(:base) 100
iex> ExLisp.call(:add, [1, 2]) 3
Use compiled functions/variables inside Lisp expressions
iex> ExLisp.eval("(calc 10)") 220
- Loading beam files output to ebin/
Outside a Mix project where .beam files are generated in ebin/ of the current directory, add the load path before calling:
Pass path with -pa when starting iex / elixir
$ iex -pa ebin iex> ExLisp.Global.add(1, 2) 3
Alternatively, add the path from within Elixir code:
Code.append_path("ebin") ExLisp.Global.add(1, 2)
=> 3
Limitations and Notes
Immutability and Circular/Infinite Lists
Since ExLisp runs on the BEAM (Erlang/Elixir) virtual machine, all runtime data structures are immutable and acyclic (DAG).
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。