Zach Beane has released the latest Quicklisp beta (January 2026), and I am pleased to have contributed to this release. Here are the highlights:
dual-numbers— Implements dual numbers and automatic differentiation using dual numbers for Common Lisp.fold— FOLD-LEFT and FOLD-RIGHT functions.function— Provides higher-order functions for composition, currying, partial application, and other functional operations.generic-arithmetic— Defines replacement generic arithmetic functions with CLOS generic functions making it easier to extend the Common Lisp numeric tower to user defined numeric types.named-let— Overloads the LET macro to provide named let functionality similar to that found in Scheme.
Selected Functions
Dual numbers
Returns a new unary function that computes the exact derivative of the given
function at any point x.
The returned function utilizes Dual Number arithmetic to perform
automatic differentiation. It evaluates f(x + ε), where
ε is the dual unit (an infinitesimal such that ε2 = 0).
The result is extracted from the infinitesimal part of the computation.
This method avoids the precision errors of numerical approximation (finite difference)
and the complexity of symbolic differentiation. It works for any function composed
of standard arithmetic operations and elementary functions supported by the
dual-numbers library (e.g., sin, exp, log).
Example
(defun square (x) (* x x))
(let ((df (derivative #'square)))
(funcall df 5))
;; => 10
Implementation Note
The implementation relies on the generic-arithmetic system to ensure that
mathematical operations within function can accept and return
dual-number instances seamlessly.
Function
Composes a binary function B(x, y) with a unary function U(z)
applied to one of its arguments.
These combinators are essential for "lifting" unary operations into binary contexts, such as when folding a sequence where elements need preprocessing before aggregation.
Example
;; Summing the squares of a list
(fold-left (binary-compose-right #'+ #'square) 0 '(1 2 3))
;; => 14 ; (+ (+ (+ 0 (sq 1)) (sq 2)) (sq 3))
FOLD
Iterates over sequence, calling function with the
current accumulator and the next element. The accumulator is initialized to
initial-value.
This is a left-associative reduction. The function is applied as:
Unlike CL:REDUCE, the argument order for function is strictly defined:
the first argument is always the accumulator, and the second
argument is always the element from the sequence. This explicit ordering eliminates ambiguity
and aligns with the functional programming convention found in Scheme and ML.
Arguments
function: A binary function taking (accumulator, element).initial-value: The starting value of the accumulator.sequence: A list or vector to traverse.
Example
(fold-left (lambda (acc x) (cons x acc))
nil
'(1 2 3))
;; => (3 2 1) ; Effectively reverses the list
Named Let
Provides the functionality of the "Named Let" construct, commonly found in Scheme.
This allows for the definition of recursive loops within a local scope without
the verbosity of LABELS.
The macro binds the variables defined in bindings as in a standard let,
but also binds name to a local function that can be called recursively
with new values for those variables.
This effectively turns recursion into a concise, iterative structure. It is the
idiomatic functional alternative to imperative loop constructs.
While commonly used for tail recursive loops, the function bound by named let is a first-class procedure that can be called anywhere or used as a value.
Example
;; Standard Countdown Loop
(let recur ((n 10))
(if (zerop n)
'blastoff
(progn
(print n)
(recur (1- n)))))
Implementation Note
The named-let library overloads the standard CL:LET
macro to support this syntax directly if the first argument is a symbol. This allows
users to use let uniformly for both simple bindings and recursive loops.
No comments:
Post a Comment