[ prog / sol / mona ]

prog


Why don't lisps have list destructuring automatically in let

1 2018-11-04 02:48

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+ ...))))
2 2018-11-04 04:22

the macroexpansions changes variable names, which is weird

Isn't that the condition for hygienic macros?

3 2018-11-04 13:39

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.

4 2018-11-04 22:05

>>3
yeah but I just want a let+ that can deal with multiple values as well
also, let+ is more idiomadic than match

5 2018-11-05 06:04

elisp has pcase-let

6 2018-11-05 06:35

ill get back to you guys when I rewrite it using standard define-macro, maybe then it won't rename the variable names

7 2018-11-05 06:54

>>6
define-macro is like Lisp's defmacro (non-hygienic) but not all Schemes have them.

8 2018-11-05 08:26

tbh list destructuring and multiple value bindings should be standard in every lisp

9 2018-11-05 08:28

>>8
*in every let in every lisp

10 2018-11-06 07:12
(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.

11 2018-11-06 10:39

>>11

Lessons learned, define-macro is the way.

It's very debatable but I'm not going to start.

12 2018-11-07 03:44

>>11
you can do anything in standard define macro, plus it's unhyiegenic
you can achieve hygiene with standard gensym or make-symbol

13 2018-11-08 12:52

>>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.

14 2018-11-09 09:25

>>13
except when they rename your bindings

15 2018-11-09 23:02

>>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)
16 2018-11-10 01:39

>>15
At this point you can just use match-left whose definition may be more obvious for someone who'd read your code.

17 2018-11-10 01:40

match-let

18 2018-11-10 04:47

>>16
actually, i reverted back and only used match-let for destructuring-lists, I still want to work with multiple values too

19 2020-09-19 13:15

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))
20 2020-09-28 05:39

Does no one use SRFI-8 any more? `receive` used to be fairly popular in SLIB times.

21


VIP:

do not edit these