aboutsummaryrefslogblamecommitdiff
path: root/_tils/2021-04-24-three-way-conditional-for-number-signs.md
blob: ec62378965ec0e104869436c7c4ec8bd6016144e (plain) (tree)
1
2
3
4
5



                                             
                  



















                                                          
                                                                                                                                   















                                                                                                                                              
                                                                                                                                                                                                          

















                                                                                                               
---

title: Three-way conditional for number signs

date: 2021-04-24 3

layout: post

lang: en

ref: three-way-conditional-for-number-signs

---

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