siiky
2022/08/22
2022/08/23
en
(Reply (and an example) at the end)
If you're a Lisper, even if you're not a Schemer, please don't skip this post! :)
Almost two years ago I wrote a macro to make it easier to work with values of an alist ("association list" i.e. list of key/value pairs; Scheme's "default" dictionary-like structure). It was called let-aref at first and it could be used to introduce a single variable with the value associated with a key of an alist -- sort of like let but for alists and for a single variable. Soon I realized I could use it for several variables if I changed it only slightly, which became alist-let.
At the time I didn't think much about it, just another tiny macro to make my life easier. But much later (only a few months ago) I needed something like it again. I went searching instead of copying it over and found nothing. Why the heck doesn't something like this exist? The only pattern matcher I know of doesn't seem to support it either.
A bit over a month ago I started thinking of making it more general, because there were lots of assumptions in the original alist-let (most relevant: keys were "simple" symbols, that is, the unquoted key was a valid variable identifier); and also of introducing it to the broader Scheme community.
Latest (original) alist-let (and variants)
I first tested the waters on #scheme and some people acknowledged such syntax would be useful, and nobody came up with readily available alternatives. A few days later I sent an RFC to srfi-discuss:
alist-let: let-like alist destructuring syntax
The goal (even though the "project" is for now still called alist-let) is to define some common pattern/syntax for the different dictionary-like types. You can find the latest (new) alist-let in this repo:
https://git.sr.ht/~siiky/alist-let
If you're a Schemer, what do you think? Send your comments to the list (preferably) or to me directly. If you're a Lisper, even if you're not a Schemer, I would also appreciate your comments. Does your Lisp of choice have something like this? How is it? Let me know!
@stack replied with lots of confusion.
Reading back what I wrote I can understand why...
Not very useful, as it is a tautology for the let macro in the first place!
Indeed but that's not it. :p
First question: what is the purpose of alist-let?
It seems you're thinking it's supposed to destructure alists at macro-expansion time? But that's not it, it's for destructuring alists at runtime.
In case you know JavaScript, alist-let is more like the following destructuring syntax:
const obj = { a: 1, b: 2, c: 3 } const { a, c } = obj // Do something with a and c console.log("a=", a, " b=", b)
If you don't know JavaScript, and because I don't like JavaScript and "an example is worth a thousand words" or something: if you're writing a CLI program you're likely to need to parse the command line arguments into (positional) arguments, flags and options. Let's say the program has the flags "--recursive", "--raw-leaves" and "--trickle", and the options "--cid-version" and "--hash".
;(defun main (opts) ...) (define (main opts) (alist-let string=? opts ; VAR KEY DEFAULT (optional) ((recursive "recursive" #f) (cid-version "cid-version" 1) (raw-leaves "raw-leaves" ) ; #f is implicitly used as the default (trickle "trickle" ) (hash "hash" "sha2-256")) (print "recursive=" recursive #\n ; recursive=#t "cid-version=" cid-version #\n ; cid-version=42 "raw-leaves=" raw-leaves #\n ; raw-leaves=#t "trickle=" trickle #\n ; trickle=#f "hash=" hash #\n ; hash="sha2-256" ))) ; parse-arguments turns something like this: '("--recursive" "--raw-leaves" "--cid-version" "42") ; Into this: '(("recursive" . #t) ("raw-leaves" . #t) ("cid-version" . 42)) (main (parse-arguments (command-line-arguments)))
The only (current) alternative I know of is to manually alist-ref each key (mentioned at the top of the email):
; VAR KEY DEFAULT (optional) (let ((recursive (alist-ref "recursive" opts string=? #t)) (cid-version (alist-ref "cid-version" opts string=? 1)) (raw-leaves (alist-ref "raw-leaves" opts string=? #f)) (trickle (alist-ref "trickle" opts string=? )) (hash (alist-ref "hash" opts string=? "sha2-256"))) ; Do something with recursive, cid-version, raw-leaves, trickle, hash (print "recursive=" recursive #\n "cid-version=" cid-version #\n "raw-leaves=" raw-leaves #\n "trickle=" trickle #\n "hash=" hash #\n))
(alist-ref key alist) is more or less (cdr (assoc key alist))
Hope this helps.
BTW I thought plists were flat alists: (k1 v1 k2 v2 ...) ?