Higher-Order Functions and Closures
;; Closures capture lexical variables
(defun make-counter (&optional (start 0))
(let ((count start))
(lambda () (incf count))))
(defparameter *c1* (make-counter))
(funcall *c1*) ; 1
(funcall *c1*) ; 2
(defun make-account (balance)
(list :deposit (lambda (amt) (incf balance amt))
:withdraw (lambda (amt) (if (>= balance amt) (decf balance amt) (error "Insufficient funds")))
:balance (lambda () balance)))
(defparameter *acc* (make-account 100))
(funcall (getf *acc* :deposit) 50) ; 150
;; Function composition and partial application
(defun compose (&rest fns)
(if (null fns)
#'identity
(let ((f (first fns)) (g (apply #'compose (rest fns))))
(lambda (&rest args) (funcall f (apply g args))))))
(funcall (compose #'1+ #'abs) -5) ; 6
(defun curry (fn &rest args1)
(lambda (&rest args2) (apply fn (append args1 args2))))
(funcall (curry #'+ 10) 5) ; 15
(mapcar (curry #'* 2) '(1 2 3)) ; (2 4 6)
;; Alexandria provides compose, curry, rcurry, conjoin, disjoin
(complement #'evenp) ; a function returning the opposite
(remove-if (complement #
…