multiple-value-bind

Started by hds1, June 28, 2017, 10:53:30 PM

Previous topic - Next topic

hds1

Hello,

i'am trying to emulate "multiple-value-bind" via read time macro. That is translate:



(mvb '(a b c .... ) '(1 2 3 ....) ...)))
into
(let (a 1 b 2 c 3 ....) ..... ))))


The idea i had is expansion during read time :

(macro (mvb) nil)
(constant 'mvb (lambda-macro (ALIST BLIST)
(letex (flat (transpose (list ALIST BLIST))))))

But this fails because i cannot pass a function or variable to 'letex.



What do i miss here ? Or is there another way ?



Thx

Heiko

rrq

#1
mmm, you might have meant something like this?
macro (mvb) nil)
(constant 'mvb (lambda-macro ()
        (extend (list 'let (map list (args 0) (args 1))) (2 (args)))))

I.e., create a let clause with the two first arguments as variable assignments, then the rest forming the body.

It breaks violently on bad syntax input of course, especially if you quote the two first lists. The input with rather be without quotes, such as for instance: (mvb (a b c) (1 2 3) (+ a b c))
You can verify the macro result e.g. by quoting the expression, as in '(mvb (a b c) (1 2 3) (+ a b c))

In any case, I'm not sure what you mean with
QuoteBut this fails because i cannot pass a function or variable to 'letex.

The first term of a letex clause is a variable binding term like that of a let clause, and then those variables get replaced by their values in the clause body, which thereafter is evaluated. A simple illustration could be
(letex ((a 3) (b 4)) (+ a b))
which of course evaluates to 7.

hds1

#2
Good idea. Looks not too bad:



(macro (mvb) nil)
(constant 'mvb (lambda-macro ()
(list 'let
      (flat (transpose (list (args 0) (args 1))))
      (args 2))))
(define (ttt)
  (mvb (a b c) (1 2 3) (println "Killroy: " (+ a b c))))

(ttt)
==>
> Killroy: 6
6


'(mvb (a b c) (1 2 3) (println "Killroy: " (+ a b c)))
==>
(let (a 1 b 2 c 3)
  (println "Killroy: " (+ a b c)))


But, (args 1) cannot be something like (sequence 1 3) or a result of a function call because it gets not evaluated during read time.

Is there a way to make (args 1) beeing evaluated during read time ?

hds1

#3
Answering myself ..

;; @syntax (m-v-b symlist valuelist body)
;;
;; @param  symlist valuelist body
;; symlist: List of var names
;; valuelist: List of values or function call which returns list of values
;; body: Operation with var names
;; @return Expanded 'let with body
;; @example
;; (m-v-b '(a b c) '(1 2 3) (+ a b c)) -> (let (a 1 b 2 c 3) (+ a b c))
;; Supposed to emulate Common Lisp multiple-value-bind macro
;; Expansion is done during Read Time.
;; Evaluation of the returned 'let body during Run Time.
(macro (m-v-b) nil)
(constant 'm-v-b (lambda-macro ()
  ;; Read Time part
 (when (or (not (quote? (args 0)))
   (not (list? (eval (args 0)))))
   (throw-error "m-v-b: first argument must be a quoted list i.e. '(a b c)"))
 (let ((lst1 (eval (args 0)))
(lst2 (map quote (eval (args 1))))) ; quote elements so that list of lists can be used
   (when (!= (length lst1)
     (length lst2))
     (throw-error
      (append "m-v-b: Argument lists length unequal. " (string lst1) " " (string lst2))))
   ;; Run Time part
   (list 'let
 (flat (transpose (list lst1 lst2)))
 (args 2)))))



(m-v-b '(a b) (transpose '((1 2)(3 4)))
(println a b))
==> (1 3)(2 4)
(m-v-b '(a b) '(3 4)
(println a b))
==> 3 4

Getting better ....