- Introduction
- Installation
- Language Overview
- Data Types
- Expressions and Control Flow
- Functions and Closures
- Variable Bindings
- Modules
- Macros
- Standard Library
- Examples
- License
MLisp is a Lisp dialect implemented in OCaml, featuring a clean syntax, lexical scoping, closures, modules, and a macro system. It provides a REPL (Read-Eval-Print Loop) for interactive development and supports both interactive and file-based execution.
- OCaml 5.0 or later
- Dune build system
- Core library and dependencies (see
mlisp.opam)
# Clone the repository
git clone <repository-url>
cd mlisp
# Install dependencies
opam install . --deps-only
# Build the project
dune build
# Install globally (optional)
dune install# Start the REPL
dune exec mlisp
# Run a MLisp file
dune exec mlisp -- <file.mlisp>MLisp uses S-expression syntax with prefix notation. All expressions are evaluated in a functional style with lexical scoping.
- Comments: Lines starting with
;;are comments - S-expressions:
(function arg1 arg2 ...) - Quoting: Use
`for quoting expressions:`fooor(quote foo)
MLisp supports integers and floating-point numbers:
42 ;; Integer
-17 ;; Negative integer
3.14 ;; Float#t ;; True
#f ;; False"hello" ;; String literal
"world" ;; Another string
"" ;; Empty string
(@ "Hello" " " "World") ;; String concatenation: "Hello World"Symbols are identifiers used for variable names and function names:
foo ;; Symbol (when evaluated)
`foo ;; Quoted symbolLists are constructed using cons pairs, and nil represents the empty list:
nil ;; Empty list
(cons 1 (cons 2 nil)) ;; List: (1 2)
(list 1 2 3) ;; List constructor: (1 2 3)
(car '(1 2 3)) ;; 1 (first element)
(cdr '(1 2 3)) ;; (2 3) (rest of list)
(atom? x) ;; #t if x is an atom, #f if it's a pairRecords provide structured data:
(record 'point (list (list 'x 10) (list 'y 20)))
(record-get point-record 'x) ;; Access fieldAll arithmetic operators support variadic arguments:
(+ 1 2) ;; 3
(+ 10 20 30) ;; 60
(- 10 5) ;; 5
(- 100 30 20) ;; 50
(* 3 4) ;; 12
(* 2 3 4) ;; 24
(/ 10 2) ;; 5
(/ 100 10 2) ;; 5
(% 10 3) ;; 1 (modulo)(== 5 5) ;; #t (equality)
(!= 5 6) ;; #t (inequality)
(< 5 10) ;; #t (less than)
(<= 5 10) ;; #t (less than or equal)
(> 10 5) ;; #t (greater than)
(>= 10 5) ;; #t (greater than or equal)(if #t 1 2) ;; Returns 1
(if #f 1 2) ;; Returns 2
(if (> 5 3) "yes" "no") ;; Returns "yes"(cond ((< 5 3) 1)
((> 5 3) 2)
((== 5 3) 3)) ;; Returns 2(and #t #t) ;; #t
(and #t #f) ;; #f
(or #t #f) ;; #t
(or #f #f) ;; #fThe begin form sequences multiple expressions and returns the value of the last one:
(begin
(print "First")
(print "Second")
42) ;; Returns 42, prints "First" and "Second"Use quote or ` to prevent evaluation:
(quote foo) ;; Symbol foo (unevaluated)
`foo ;; Same as (quote foo)
(quote (1 2 3)) ;; List (1 2 3) (unevaluated)(lambda (x y) (+ x y)) ;; Anonymous function
(define add (lambda (x y) (+ x y)))
(add 5 3) ;; 8The defun form provides a convenient way to define named functions:
(defun square (n) (* n n))
(square 5) ;; 25(defun factorial (n)
(if (== n 0)
1
(* n (factorial (- n 1)))))
(factorial 5) ;; 120MLisp supports lexical scoping and closures:
(define make-adder (lambda (n)
(lambda (x) (+ x n))))
(define add5 (make-adder 5))
(add5 10) ;; 15(define apply-twice (lambda (f x) (f (f x))))
(defun inc (n) (+ n 1))
(apply-twice inc 5) ;; 7The apply function applies a function to a list of arguments:
(define nums '(1 2 3 4 5))
(apply + nums) ;; 15
(define args '(6 7))
(apply * args) ;; 42Global variable definition:
(define x 42)
(define y (+ 5 3))
(define greeting "Hello")Parallel bindings (evaluated simultaneously):
(let ((x 5)
(y 10))
(+ x y)) ;; 15Sequential bindings (evaluated in order):
(let* ((x 5)
(y (* x 2)))
y) ;; 10Recursive bindings for mutually recursive functions:
(letrec ((is-even
(lambda (n)
(if (== n 0)
#t
(is-odd (- n 1)))))
(is-odd
(lambda (n)
(if (== n 0)
#f
(is-even (- n 1))))))
(is-even 10)) ;; #tMLisp provides a module system for code organization and encapsulation.
(module math-constants (export pi e)
(define pi 3.14159)
(define e 2.71828));; Import all exports
(import math-constants)
pi ;; 3.14159
;; Selective import
(import arithmetic add subtract)
(add 10 5) ;; 15
;; Import with alias
(import string-utils :as str)(module arithmetic (export add subtract multiply)
(define add (lambda (x y) (+ x y)))
(define subtract (lambda (x y) (- x y)))
(define multiply (lambda (x y) (* x y))))MLisp supports hygienic macros for code generation:
(defmacro double (x)
(list '+ x x))
(define result (double 5)) ;; Expands to (+ 5 5) = 10;; When macro
(defmacro when (condition body)
(list 'if condition body (quote nil)))
(when #t (print "Hello")) ;; Prints "Hello"
(when #f (print "Hello")) ;; Does nothing
;; Macro generating let binding
(defmacro with-x (val body)
(list 'let (list (list 'x val)) body))
(with-x 10 (+ x 5)) ;; 15Macros receive their arguments as unevaluated S-expressions and return S-expressions that are then evaluated.
MLisp includes a comprehensive standard library loaded automatically.
(null? '()) ;; #t
(length '(1 2 3)) ;; 3
(append. '(1 2) '(3 4)) ;; (1 2 3 4)
(take 2 '(1 2 3 4)) ;; (1 2)
(drop 2 '(1 2 3 4)) ;; (3 4)
(mergesort '(3 1 4 2)) ;; (1 2 3 4)
(zip. '(1 2) '(a b)) ;; ((1 a) (2 b))(cons 1 '(2 3)) ;; (1 2 3)
(car '(1 2 3)) ;; 1
(cdr '(1 2 3)) ;; (2 3)
(list 1 2 3) ;; (1 2 3)
(atom? x) ;; #t if x is an atom
(symbol? x) ;; #t if x is a symbol(null. x) ;; Check if list is empty
(and. x y) ;; Logical AND
(not. x) ;; Logical NOT
(caar ls) ;; (car (car ls))
(cadr ls) ;; (car (cdr ls))(print "Hello") ;; Print to stdout
(println "Hello") ;; Print with newline
(getline) ;; Read a line from stdin
(getchar) ;; Read a character (returns integer)(int->char 65) ;; Convert integer to character symbol
(symbol-concat 'a 'b) ;; Concatenate two symbols(assert (= result 10)) ;; Assert condition(defun factorial (n)
(if (== n 0)
1
(* n (factorial (- n 1)))))
(factorial 5) ;; 120(defun fib (n)
(if (< n 2)
n
(+ (fib (- n 1)) (fib (- n 2)))))
(fib 8) ;; 21(define make-counter (lambda ()
(let ((count 0))
(lambda ()
(define count (+ count 1))
count))))
(define counter1 (make-counter))
(counter1) ;; 1
(counter1) ;; 2
(counter1) ;; 3(module counter-mod (export increment get-count reset)
(define count 0)
(define increment (lambda ()
(define count (+ count 1))
count))
(define get-count (lambda () count))
(define reset (lambda ()
(define count 0)
count)))
(import counter-mod)
(increment) ;; 1
(increment) ;; 2
(get-count) ;; 2
(reset) ;; 0This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

