THIS IS A LIST
A LIST
()This is a list.
ANOTHER LIST
(1 2 3)So is this. It has three numbers.
NESTED LISTS
((10 11 12) (1 2 3))This is three lists. One list contains two nested lists.
ASSOCIATIVE LISTS
((:micah . "lisper")
(:sussman . "lisper")
(:joe-blow . "jai guy")
(:dhh . "ruby boob"))This is an associative list, also called an alist. Lists can be used as tables storing key-value pairs.
Symbols that begin with : are called keywords. Keywords are evaluated to themselves.
SYMBOL
micahThis is a symbol. A symbol holds a reference to some data.
FUNCTION CALLS
(say-hello) ; => "Hello!"This is a list with a symbol. The first item in a list is treated as the name of a function to be called.
ARGUMENTS
(person-birthday :micah '((:micah . "1985-12-14")
(:takae . "1987-11-19")
(:mom . "1955-02-12")
(:papa . "1952-07-31"))) ; => "1985-12-14"If there are other elements in the list besides the function name, they are passed as arguments to the function. Arguments are evaluated first--from left to right--before being passed to the function.
FUNCTION DEFINITIONS
(defun person-birthday (name db) (cdr (assoc name db)))This is how you create a function. There is one list that contains two symbols and two nested lists. The first element, defun, is a macro. The second element, person-birthday, is a name to give to the function. (name db) is a lambda-list that defines the arguments to the function.(cdr (assoc name db)) is another list--the body of the function.
QUOTING
(quote (person-birthday :micah '((:micah . "1985-12-14")
(:takae . "1987-11-19")
(:mom . "1955-02-12")
(:papa . "1952-07-31"))))
; => (PERSON-BIRTHDAY :MICAH
; '((:MICAH . "1985-12-14")
; (:TAKAE . "1987-11-19")
; (:MOM . "1955-02-12")
; (:PAPA . "1952-07-31")))Quoting a list returns the literal list object without evaluating its contents. Symbols are upcased.
READER MACROS
'(person-birthday :micah '((:micah . "1985-12-14")
(:takae . "1987-11-19")
(:mom . "1955-02-12")
(:papa . "1952-07-31")))
; => (PERSON-BIRTHDAY :MICAH
; '((:MICAH . "1985-12-14")
; (:TAKAE . "1987-11-19")
; (:MOM . "1955-02-12")
; (:PAPA . "1952-07-31")))' is a reader macro. It performs the same function as the above call to quote.
CODE IS DATA
(quote (person-birthday :micah '((:micah . "1985-12-14")
(:takae . "1987-11-19")
(:mom . "1955-02-12")
(:papa . "1952-07-31"))))
; => (PERSON-BIRTHDAY :MICAH
; '((:MICAH . "1985-12-14")
; (:TAKAE . "1987-11-19")
; (:MOM . "1955-02-12")
; (:PAPA . "1952-07-31")))
(eval '(person-birthday :micah '((:micah . "1985-12-14")
(:takae . "1987-11-19")
(:mom . "1955-02-12")
(:papa . "1952-07-31"))))
; => "1985-12-14"The first list is a function call to quote. It returns the literal representation of its argument.
The the second list is a function call to eval. It will take the data it receives and evaluate it as code.
I repeat: it takes the literal representation of data and evaluates it as code. The code is data.
DATA IS CODE
(defun tree-type-of (x)
(cond ((null x) nil)
((symbolp x)
(cond ((macro-function x) (list 'macro))
((and (boundp x) (symbol-function x)) (list 'fun))
((and (boundp x) (symbol-value x)) (list 'var))
(t (list 'symbol))))
((numberp x) (list 'number))
((atom x) (list (type-of x)))
(t (and (append (tree-type-of (car x))
(tree-type-of (cdr x)))))))
(tree-type-of '(defun cube-and-double (x) (* 2 (* x x x))))
; => (MACRO SYMBOL SYMBOL FUN NUMBER FUN SYMBOL SYMBOL SYMBOL)
Code can be traversed and transformed as data.
MACRO DEFINITIONS
(defmacro to-keyword (name)
(typecase name
(keyword name)
(string (intern (string-upcase name) :keyword))
(symbol (intern (symbol-name name) :keyword))
(t "The argument must be either a keyword, string, or symbol.")))
(to-keyword :micah)
; => :MICAH
(to-keyword "micah")
; => :MICAH
(to-keyword micah)
; => :MICAH
This is a macro. It's like a function, but it writes code. This macro can turn a symbol or string passed to it into a keyword.
REWRITING CODE
(defmacro person-birthday-macro (name db)
`(cdr (assoc (to-keyword ,name) ,db)))
;; This code...
(person-birthday-macro micah '((:micah . "1985-12-14")
(:takae . "1987-11-19")
(:mom . "1955-02-12")
(:papa . "1952-07-31")))
;; ...transforms into this code...
(cdr
(assoc (to-keyword micah)
'((:micah . "1985-12-14") (:takae . "1987-11-19") (:mom . "1955-02-12")
(:papa . "1952-07-31"))))
;; ...which finally completes its transformation into this code:
(cdr
(assoc :micah
'((:micah . "1985-12-14") (:takae . "1987-11-19") (:mom . "1955-02-12")
(:papa . "1952-07-31"))))
Macros take code as data and rewrite it into other code.
SQL QUERY MACRO
(sxql:select ((:as (:coalesce (:sum :leg.entry_amount) 0) :amount)
(:as :leg.entry_currency :currency))
(sxql:from (:as :almighty_account :account))
(sxql:inner-join (:as :almighty_leg :leg) :on (:= :leg.account_id :account.id))
(sxql:inner-join (:as :almighty_transaction :tran) :on (:= :leg.transaction_id :tran.id))
(sxql:where (:and (:= :account.id (m:object-id account))
(:<= :tran.date as-of)))
(sxql:group-by :leg.entry_currency))This is SXQL code. It's a library for generating SQL queries using macros like select, from, etc.
HTML MACRO
(define-component ac-skeleton (&key title children)
(let ((html-class (string-downcase "dark"))
(html-lang "en"))
(</>
(html :class html-class :lang html-lang
(head
(title (str:concat (string-upcase title) " /// " (string-upcase "almightylisp.com")))
(meta :charset "utf-8")
(meta :name "viewport" :content "width=device-width, initial-scale=1")
(link :href "css/almightylisp.css" :rel "stylesheet" :type "text/css")
(script
:src "https://unpkg.com/[email protected]/dist/htmx.js"
:integrity "sha384-oeUn82QNXPuVkGCkcrInrS1twIxKhkZiFfr2TdiuObZ3n3yIeMiqcRzkIcguaof1"
:crossorigin "anonymous")
(script :src "https://unpkg.com/[email protected]"))
(body :class "font-berkeley bg-primary text-primary-50"
children)))))This is code from the almighty-html library. The </> macro generates HTML and can create components.
A NEW LISP LANGUAGE
(declare withdraw (AccountName -> Amount -> BankM (BankResult Account)))
(define (withdraw account-name amount)
"Withdraw AMOUNT from account with ACCOUNT-NAME, returning the Account for convenience."
(do
(protection? <- (asks overdraft-protection_))
(minimum <- (asks minimum-balance_))
(do-resultT
(err-ifM (< amount 0) (InvalidWithdrawal amount))
(acc <- (get-accountM account-name))
(map-errM
(fn (er)
(Unknown
(s:concat "Cannot withdraw from an invalid account: "
(into er))))
(check-account-is-valid acc))
(let new-account = (subtract-balance amount acc))
(if (and protection?
(< (.balance new-account) minimum))
(pure (Err (InvalidWithdrawal amount)))
(set-account new-account)))))
This is Coalton, a new programming language written in Common Lisp with a Haskell-inspired type system. It's "just a macro".
It all starts with a list.

Coming Soon...