I defined this in my Scheme and it kinda works, but for some reason the macroexpansions changes variable names, which is weird
(define-syntax let+
(syntax-rules ()
((let+ (((pattern ...) list) bindings ...)
body body+ ...)
(reverse-args apply list
(lambda* (pattern ...)
(let+ (bindings ...)
body body+ ...))))
((let+ (((pattern pattern+ ... . tail) improper-list)
bindings ...)
body body+ ...)
(let ((pattern (car improper-list)))
(let+ (((pattern+ ... . tail) (cdr improper-list))
bindings ...)
body body+ ...)))
((let+ ((let-stuff ...) bindings ...)
body body+ ...)
(let ((let-stuff ...))
(let+ (bindings ...)
body body+ ...)))
((let+ () body body+ ...)
(begin body body+ ...))))
the macroexpansions changes variable names, which is weird
Isn't that the condition for hygienic macros?
Some lisps have a 'match' macro that does destructuring-binds such as
(define x
(match *something*
((a b a) (cons a a a b))
((_ _ a) a)
(else #f)))
Hygienic macros create new bindings with names that cannot exist anywhere else but when they don't deal in macro-introduced names, they should substitute for the correct referred name.
>>3
yeah but I just want a let+ that can deal with multiple values as well
also, let+ is more idiomadic than match
elisp has pcase-let
ill get back to you guys when I rewrite it using standard define-macro, maybe then it won't rename the variable names
>>6
define-macro
is like Lisp's defmacro
(non-hygienic) but not all Schemes have them.
tbh list destructuring and multiple value bindings should be standard in every lisp
>>8
*in every let in every lisp
(define-macro (let+ bindings . body)
(if (null? bindings) `(begin ,@body)
(cond ((atom? (caar bindings))
`(let (,(car bindings))
(let+ ,(cdr bindings) ,@body)))
((list? (caar bindings))
`(apply (lambda* ,(caar bindings)
(let+ ,(cdr bindings) ,@body))
,(cadar bindings)))
(else
`(let ((,(caaar bindings) (car ,(cadar bindings)))
(,(cdaar bindings) (cdr ,(cadar bindings))))
(let+ ,(cdr bindings) ,@body))))))
Rate working version.
Lessons learned, define-macro is the way.
Lessons learned, define-macro is the way.
It's very debatable but I'm not going to start.
>>11
you can do anything in standard define macro, plus it's unhyiegenic
you can achieve hygiene with standard gensym or make-symbol
>>12
You can also achieve unhygiene in hygienic systems except you won't have a bug due to forgetting a gensym somewhere. Hygienic systems are objectively superior.
>>13
except when they rename your bindings
>>3
you're right, I just ended up doing this
(define-macro (synonymize synonym existing)
`(define-macro (,synonym . body) (cons ',existing body)))
(synonymize let+ match-let)
>>15
At this point you can just use match-left
whose definition may be more obvious for someone who'd read your code.
match-let
>>16
actually, i reverted back and only used match-let for destructuring-lists, I still want to work with multiple values too
https://srfi.schemers.org/srfi-201/srfi-201.html actually proposes something along these lines, that reminds me of Elisp pcase:
(let* ((`(,a ,b) `(,c) (values '(1 2) '(3)))
((d e `(,f . ,_) (values 4 5 '(6 7)))))
(+ a b c d e f))
Does no one use SRFI-8 any more? `receive` used to be fairly popular in SLIB times.