FOL: Functional Object Lisp
June 24, 2026 · View on GitHub
FOL is a Clojure dialect that combines persistent data structures (from Clojure), CLOS-style object orientation with persistent objects, and array programming capabilities (inspired by Q/APL). Every value is an object backed by persistent structures enabling efficient structural sharing and immutability. FOL transpiles to Common Lisp (currently only SBCL has been tested and is supported).
Current version
0.1.1
Features
- Persistent Data Structures: Vectors, dictionaries, sets, bags with structural sharing
- Object-Oriented Programming: CLOS-style generic functions, methods, and classes
- Array Programming: Vectorized operators, axis-aware adverbs, multi-dimensional operations
- Functional Programming: First-class functions, closures, partial application, memoization
- Immutability by Default: All data structures are immutable; mutation assoc/dissoc creating shared structures (collections) or new objects (CLOS objects)
- Meta-Object Protocol: Full introspection and reflection capabilities
- Lazy Sequences: Infinite sequences with on-demand evaluation
Quick Start
Building
cd src
sbcl --noinform --non-interactive \
--eval "(push (truename \".\") asdf:*central-registry*)" \
--eval "(asdf:load-system :fol-compiler)"
Running Tests
cd src && sbcl --noinform --non-interactive \
--eval "(push (truename \".\") asdf:*central-registry*)" \
--eval "(asdf:load-system :fol-compiler/tests)" \
--eval "(fol.compiler.tests:run-compiler-tests)"
Using the REPL
cd src && sbcl
(push (truename ".") asdf:*central-registry*)
(asdf:load-system :fol-compiler)
(use-package :fol.core)
; Now you can evaluate FOL code
(+ 1 2 3) ; => 6
(def x [1 2 3 4 5])
(map #(* % 2)) ; => [2 4 6 8 10]
Project Structure
fol/
├── src/ # Compiler and runtime
│ ├── compiler.lisp # Main compiler (parse/emit)
│ ├── ast.lisp # AST node definitions
│ ├── package.lisp # Package definitions
│ ├── collections.lisp # Collection classes
│ ├── array-functions.lisp # Vectorized operators
│ ├── adverbs.lisp # Axis-aware operations
│ ├── advanced-array-operations.lisp # Reshape, slice, transpose
│ ├── fol-compiler.asd # ASDF system definition
│ └── tests/ # Test suites
├── docs/ # Documentation
│ ├── manual/ # User manual
│ │ ├── FOL-MANUAL.md # Main reference
│ │ ├── array-operations.md # Array operator reference
│ │ ├── adverbs.md # Adverb reference
│ │ └── ... # Other documentation
│ └── caching/ # Research papers
├── benchmarks/ # Performance benchmarks
├── vscode/ # VSCode extension
└── README.md # This file
Documentation
- FOL Manual - Complete language reference
- Array Operations - Phase 1: Vectorized operators
- Adverbs - Phase 2: Axis-aware operations
- Collections - Vector, dict, set operations
- Special Forms - if, do, fn, loop, recur, etc.
Architecture
-Array Programming System
Generic Operators
- Vectorized arithmetic:
+,-,*,/ - Broadcasting support for scalar-vector operations
- Varargs reduction chains
Adverbs
- Axis-aware operations:
fold,scan,each,window - Statistics:
sum,mean,variance,std-dev - Transformations:
array-reverse,map-array,zip - Partitioning:
array-partition,array-take,array-drop
Advanced Operations
- Shape operations:
shape,rank,array-size,flatten,reshape - Axis operations:
sum-axis,mean-axis,max-axis,min-axis - Slicing:
slice,get-slice,put-slice - Concatenation:
concat-arrays,stack,hstack,vstack - Transposition:
transpose
159/159 tests passing (100%)
Example Usage
Array Operations
; Vectorized arithmetic
(+ [1 2 3] [4 5 6]) ; => [5 7 9]
(* [1 2 3] 10) ; => [10 20 30]
; Axis-aware reductions
(sum [[1 2 3] [4 5 6]] :axis 0) ; => [5 7 9]
(mean [[1 2 3] [4 5 6]] :axis 0) ; => [2.5 3.5 4.5]
; Reshaping and transposition
(reshape [1 2 3 4 5 6] [2 3]) ; => [[1 2 3] [4 5 6]]
(transpose [[1 2 3] [4 5 6]]) ; => [[1 4] [2 5] [3 6]]
Collections
; Vectors
(def v [1 2 3 4 5])
(get v 0) ; => 1
(assoc v 2 99) ; => [1 2 99 4 5]
; Dictionaries
(def m {:name "FOL" :year 2026})
(get m :name) ; => "FOL"
; Sets
(def s #{1 2 3})
(contains? s 2) ; => true
Functional Programming
; Higher-order functions
(map #'(lambda (x) (* x 2)) [1 2 3]) ; => [2 4 6]
(filter #'(lambda (x) (> x 2)) [1 2 3 4 5]) ; => [3 4 5]
(reduce #'+ [1 2 3 4 5]) ; => 15
; Composition
(comp #'inc #'double) ; Returns function
; Memoization
(def fib (memoize #'(lambda (n) ...)))
Contributing
When modifying FOL:
- Run tests before committing changes
- Update documentation if you change public APIs
- Follow naming conventions: predicate functions end with
?, functions that modify state end with! - Keep it immutable: Default to persistent data structures
Performance
Benchmarks available in benchmarks/ directory. Key results:
- Array Operations: 2-4× faster than equivalent CL loops with broadcasting
- Collections: Structural sharing reduces memory usage by 60-70% vs. mutable copies
- Dispatch Caching: 2.3× speedup via generation-based cache validation
Known Limitations
- Transpiler supports SBCL Only: Dispatch caching and advanced features require SBCL
- Lexical Scope: No dynamic scoping (use explicit binding forms)
License
MIT License - See LICENSE file for details
Authors
- Frank Adrian (creator)
- Claude (AI assistant contributions to testing, documentation, optimization)
References
- Paper: "FOL: A Functional Object Lisp" - European Lisp Symposium 2026
- Inspired by: Clojure, Q, APL, Common Lisp, Dylan
- Dispatch Caching Research: Multi-language analysis of dispatch caching strategies
Last Updated: June 22, 2026
Status: Production Ready (3031/3031 tests passing)