šŸ’¾ Archived View for idiomdrottning.org ā€ŗ sloppy-tree-accessors captured on 2024-08-18 at 19:18:15. Gemini links have been rewritten to link to archived content

View Raw

More Information

ā¬…ļø Previous capture (2023-01-29)

-=-=-=-=-=-=-

Sloppy tree accessors

I learned Scheme before Common Lisp and Emacs Lisp (well, my very first exposure was to the very basics of Emacs Lisp, I didnā€™t even get to defun part), but Iā€™ve done my fair share of Common Lisp since and Iā€™ve been vindicated in one thing I kinda independently invented and Iā€™m sure a lot of other impatient, lazy, and hubristic hacks came up with the same thing.

I often found myself wanting to do things on car, if there is a car. Or on cdr, if there is a cdr. And so on.

I called these accessors scar and scdr, and I at first thought ā€œs for ā€˜safeā€™ since they wonā€™t error! I am so smart!ā€ but soon enough realized these were anything but safe, since they fail silently!

I started using them a little bit less, andā€¦ veeery carefully. Guiltily and self-deprecatingly, I started thinking of the s as standing for Sandraā€™s. When I made brev, which has an arbitrary-depth generator for them (you can (make-sloppy-tree-accessor scdaaddaaddadddadaaaadr) or whatever), I came up with the name ā€œsloppyā€ and started feeling less bad.

All of this stems from '() and #f being two separate values in Scheme where Common Lisp and Emacs Lisp only has nil. So on there, you can (cadar ()) and it doesnā€™t bork. Vindicated!

I feel that with sloppy tree accessors carefully and judiciously applied, and eif (which treats empty as falsy) as an option next to the normal, safe if, we can have the best of both worlds. Convenience when we know what weā€™re doing, but retaining the ability to discriminate between these value types when we need to.

brev

Update

Elias wrote in, asking:

Being someone who definitely prefers CL, I wonder when you need to discriminate between them?

I love the convenience of CL in this particular regard.

Hereā€™s my take: 90% of the time I donā€™t care. 8% I want the CL style. 2% of the time I do want them as separate.

One example is when you have a function that can return ``#f if it doesnā€™t find what itā€™s looking for, or a list (including the empty list) if it does. Only way to do this on CL is with boxing (sorta like the Haskell ā€œJust Maybeā€ ridiculousness).

alist-ref from Chickenā€™s base module is an obvious example.

(aif (alist-ref foo bar)
     (frobnicate it)
     (not found so update the alist instead))

To get the CL behavior, thatā€™s why I made eif which is an aif that does treat empty as falsy.

As an aside, those ā€œ90% of the time when I donā€™t careā€, it does find me some bugs, so. šŸ¤·šŸ»ā€ā™€ļø (Thatā€™s also what all those straight-jacket typed languages fans keep writing in about when they hear that I love dynamic typing and hate the redundant human compiler at work annotating types and duplicating code. Even though brev has dependent types (albeit runtime, not compile time).)

But in CLā€™s defense, half of those ā€œbugsā€ wouldnā€™t even be bugs in CL. If Iā€™m like

(if (eq foo (car bar))
    this
    that)

then thatā€™s just as good (on CL) and non-buggy (on CL) as the annoying, overly explicit Scheme style of

(if (and (pair? bar)
         (eq? foo (car bar)))
    this
    that)

Thatā€™s what sloppy tree accessors fix:

(if (eq? foo (scar bar))
    this
    that)

Brev. Making Scheme almost as good as CL since 2021 šŸ¤¦šŸ»ā€ā™€ļø