blob: 6971827e99e3dfc330ea6d8580946624d825e4d0 (
plain) (
tree)
|
|
---
title: Three-way conditional for number signs on Lisp
date: 2021-04-24 3
update: 2021-08-14
categories: lisp scheme common-lisp
---
A useful macro from Paul Graham's [On Lisp][on-lisp] book:
```lisp
(defmacro nif (expr pos zero neg)
(let ((g (gensym)))
`(let ((,g ,expr))
(cond ((plusp ,g) ,pos)
((zerop ,g) ,zero)
(t ,neg)))))
```
After I looked at this macro, I started seeing opportunities to using it in
many places, and yet I didn't see anyone else using it.
The latest example I can think of is section 1.3.3 of [Structure and
Interpretation of Computer Programs][sicp], which I was reading recently:
```scheme
(define (search f neg-point pos-point)
(let ((midpoint (average neg-point pos-point)))
(if (close-enough? neg-point post-point)
midpoint
(let ((test-value (f midpoint)))
(cond ((positive? test-value)
(search f neg-point midpoint))
((negative? test-value)
(search f midpoint pos-point))
(else midpoint))))))
```
Not that the book should introduce such macro this early, but I couldn't
avoid feeling bothered by not using the `nif` macro, which could even remove
the need for the intermediate `test-value` variable:
```scheme
(define (search f neg-point pos-point)
(let ((midpoint (average neg-point pos-point)))
(if (close-enough? neg-point post-point)
midpoint
(nif (f midpoint)
(search f neg-point midpoint)
(midpoint)
(search f midpoint pos-point)))))
```
It also avoids `cond`'s extra clunky parentheses for grouping, which is
unnecessary but built-in.
As a macro, I personally feel it tilts the balance towards expressivenes
despite its extra cognitive load toll.
[on-lisp]: http://www.paulgraham.com/onlisptext.html [sicp]:
https://mitpress.mit.edu/sites/default/files/sicp/index.html
|