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

micah

This 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...