Fennel
2016fragletMCP + fragletc
Fennel is a programming language that brings together the simplicity and elegance of Lisp with the ubiquity and performance of Lua. It's a Lisp that compiles to Lua, giving you the expressive power of parentheses with the practicality of one of the most embedded scripting languages in the world.
What makes Fennel special?
๐ Lua's Little Lisp: Fennel compiles down to readable Lua code, making it perfect for game development, embedded scripting, and anywhere Lua is used.
๐ Zero-cost abstractions: All Fennel code compiles to efficient Lua with no runtime overhead.
๐ฏ Gradual adoption: You can use Fennel alongside existing Lua code, making migration painless.
โก Macros that matter: Real Lisp macros let you extend the language itself, not just write functions.
Fun Facts
- Fennel was created by Phil Hagelberg (technomancy), who also created Leiningen for Clojure
- The name "Fennel" comes from the herb, continuing the botanical theme of many Lisp dialects
- It's used in the Lua ecosystem where people want Lisp's power but Lua's reach
- You can write entire game scripts in Fennel and compile them to vanilla Lua
Fennel proves that sometimes the best way forward is to go back to the elegant fundamentals of Lisp while embracing the practical world of modern runtime environments.
;; Simple and beautiful
(print "Hello World!")Hello World
#!/usr/bin/env fennel
(print "Hello World!")Coding Guide
Language Version
Fennel (latest via luarocks)
Execution Model
- Compiled to Lua bytecode, then executed by Lua runtime
- Fragment executes as top-level code in the script
- Fennel compiler processes the fragment, then Lua executes the result
- Output must be explicit (
print,io.write)
Key Characteristics
- Lisp syntax (parentheses-based, prefix notation)
- Compiles to Lua, so has access to all Lua features
- Dynamic typing (inherited from Lua)
- Case-sensitive
- Tables are the primary data structure (Lua tables)
- Functions are first-class values
- Supports destructuring, pattern matching, and macros
Fragment Authoring
Write valid Fennel code. Your fragment becomes the script body. Code runs at the top level of the script. Define helper functions before using them. Fennel code is compiled to Lua before execution.
Available Libraries/Packages
Standard Lua libraries are available:
string- string manipulationtable- table operationsmath- mathematical functionsio- input/output operationsos- operating system interface
Fennel-specific features:
- Macros via
macroandmacros - Pattern matching via
match - Destructuring in
let,var, function parameters - Table comprehensions
Common Patterns
- Print:
(print "message") - Local variables:
(local message "Hello") - Tables:
(local list [1 2 3]) - Functions:
(fn greet [name] (.. "Hello, " name "!")) - Iteration:
(each [i value (ipairs list)] (print value)) - Table iteration:
(each [key value (pairs table)] (print key value)) - Pattern matching:
(match x 1 "one" 2 "two" _ "other") - Destructuring:
(let [[a b c] [1 2 3]] (print a b c))
Examples
;; Simple output
(print "Hello, World!")
;; Function definition
(fn greet [name]
(.. "Hello, " name "!"))
(print (greet "Alice"))
;; Table processing
(local numbers [1 2 3 4 5])
(local sum (accumulate [sum 0
i value (ipairs numbers)]
(+ sum (* value value))))
(print (.. "Sum of squares: " sum))
;; Pattern matching
(fn classify [n]
(match n
0 "zero"
1 "one"
(where n (< n 10)) "single digit"
_ "other"))
(print (classify 5))
;; Destructuring
(let [[first second & rest] [1 2 3 4 5]]
(print first second)
(print "Rest:" rest))
;; Working with tables
(local person {:name "Alice" :age 30})
(print (.. "Name: " (. person :name)))
(print (.. "Age: " (. person :age)))
;; String operations
(print (string.upper "hello world"))
(print (table.concat ["apple" "banana" "cherry"] ", "))Caveats
- Fennel compiles to Lua, so Lua limitations apply
- Use
localfor variables to avoid globals - Table access uses
.operator:(. table :key)or(. table key) - String concatenation uses
..operator - Function calls use parentheses:
(function arg1 arg2) - Macros are compile-time, not runtime
Fraglet Scripts
Echo Args
#!/usr/bin/env -S fragletc --vein=fennel
(print (string.format "Args: %s" (table.concat arg " ")))Stdin Upper
#!/usr/bin/env -S fragletc --vein=fennel
(each [line (io.lines)]
(print (string.upper line)))Test
#!/usr/bin/env -S fragletc --vein=fennel
(print "Hello World!")