Page 1 of 1

multiple-value-bind

PostPosted: Thu Jun 29, 2017 5:53 am
by hds1
Hello,
i'am trying to emulate "multiple-value-bind" via read time macro. That is translate:

Code: Select all
(mvb '(a b c .... ) '(1 2 3 ....) ...)))
into
(let (a 1 b 2 c 3 ....) ..... ))))


The idea i had is expansion during read time :
Code: Select all
(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

Re: multiple-value-bind

PostPosted: Thu Jun 29, 2017 9:18 am
by ralph.ronnquist
mmm, you might have meant something like this?
Code: Select all
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:
Code: Select all
(mvb (a b c) (1 2 3) (+ a b c))

You can verify the macro result e.g. by quoting the expression, as in
Code: Select all
'(mvb (a b c) (1 2 3) (+ a b c))


In any case, I'm not sure what you mean with
But 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
Code: Select all
(letex ((a 3) (b 4)) (+ a b))

which of course evaluates to 7.

Re: multiple-value-bind

PostPosted: Thu Jun 29, 2017 7:22 pm
by hds1
Good idea. Looks not too bad:

Code: Select all
(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

Code: Select all
'(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 ?

Re: multiple-value-bind

PostPosted: Thu Jun 29, 2017 7:36 pm
by hds1
Answering myself ..
Code: Select all
;; @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)))))


Code: Select all
(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 ....