From 020c1e77489b772f854bb3288b9c8d2818a6bf9d Mon Sep 17 00:00:00 2001 From: EuAndreh Date: Fri, 18 Apr 2025 02:17:12 -0300 Subject: git mv src/content/* src/content/en/ --- src/content/en/tils/2021/04/24/scm-nif.adoc | 61 +++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 src/content/en/tils/2021/04/24/scm-nif.adoc (limited to 'src/content/en/tils/2021/04/24/scm-nif.adoc') diff --git a/src/content/en/tils/2021/04/24/scm-nif.adoc b/src/content/en/tils/2021/04/24/scm-nif.adoc new file mode 100644 index 0000000..2ea8a6f --- /dev/null +++ b/src/content/en/tils/2021/04/24/scm-nif.adoc @@ -0,0 +1,61 @@ += Three-way conditional for number signs on Lisp +:categories: lisp scheme common-lisp +:sort: 2 +:updatedat: 2021-08-14 + +:on-lisp: https://www.paulgraham.com/onlisptext.html +:sicp: https://mitpress.mit.edu/sites/default/files/sicp/index.html + +A useful macro from Paul Graham's {on-lisp}[On Lisp] book: + +[source,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 {sicp}[Structure and +Interpretation of Computer Programs], which I was reading recently: + +[source,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: + +[source,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. -- cgit v1.2.3