Skip to content

Instantly share code, notes, and snippets.

@wobh
Last active August 29, 2015 14:12
Show Gist options
  • Save wobh/cf9ad338f4aa645a6d38 to your computer and use it in GitHub Desktop.
Save wobh/cf9ad338f4aa645a6d38 to your computer and use it in GitHub Desktop.
Common Lisp quadratic formula (a macrolet example)
;;; One use of `macrolet' is to simplify purely structural concerns in
;;; one's functions. As one example, consider this implementation of
;;; the quadratic formula:
(defun quadratic (a b c)
(macrolet ((plus-or-minus-div (x y z)
`(values (/ (+ ,x ,y) ,z) (/ (- ,x ,y) ,z))))
(plus-or-minus-div (- b) (sqrt (- (* b b) (* 4 a c))) (* 2 a))))
;;; Although there's still some redundancy, it's contained to the point
;;; where further abstraction is unlikely to be useful.
# Quadratic formula
require 'mathn'
def quadratic(a, b, c)
x = -b
y = Math.sqrt( (b**2) - (4 * a * c) )
z = 2 * a
[:+, :-].map { |op| (x.send(op, y)) / z }
end
# When exercised, Ruby grants an admirable concision and clarity.
# Even where the clarity seems compromised, it's at least sort of cute.
# [:+, :-]
@wobh
Copy link
Author

wobh commented Dec 31, 2014

Note: if one needed a quadratic function like this, one would want to implement it like the Ruby one, above. The Lisp one demonstrates a structural abstraction, however, more practically, consider that the values of x, y, z aren't computed (or even known) until after the macroexpansion, which means in the lisp implementation they get computed twice. You'd want to consider something like this:

(defun quadratic (a b c)
  (let ((x (- b))
        (y (rationalize (sqrt (- (* b b) (* 4 a c)))))
        (z (* 2 a)))
    (values-list
     (mapcar (lambda (op)
               (/ (funcall op x y) z))
             (list #'+ #'-)))))

Not as cute, though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment