a quasiquote implementation in newLisp

For the Compleat Fan
Locked
jsmall
Posts: 26
Joined: Mon Sep 20, 2004 1:44 am

a quasiquote implementation in newLisp

Post by jsmall »

The following macro and function define
a quasiquote / unquote mechanism in newlisp.

Note the use of uq and uq@.

Code: Select all


  ;; usage:  (qq (x y (uq (+ 1 2)) (uq@ (list 1 2 3))))
  ;;  ==>  (x y 3 1 2 3)

  (define-macro (qq s-expr)
    (qq-eval s-expr))


  ;; Since qq is a macro you can't use (args) within.
  ;; Use qq-eval instead which is not a macro and thus
  ;; (args) will not capture the qq's (args).

  ;; usage:  (qq-eval '(x y (uq (+ 1 2)) (uq@ (list 1 2 3))))
  ;;  ==>  (x y 3 1 2 3)


  (define (qq-eval s-expr , i)
    (if (list? s-expr)
      (begin
        (setq i 0)
        (while (< i (length s-expr))
          (let ((ss-expr (nth i s-expr)))
            (if (list? ss-expr)
              (cond 
                ((= 'uq (first ss-expr))
                  (nth-set i s-expr (eval (qq-eval (last ss-expr))))
                  (inc 'i))
                ((= 'uq@ (first ss-expr))
                  (let ((ss-exprs (eval (qq-eval (last ss-expr)))))
                    (if (list? ss-exprs)
                      (begin
                        (pop s-expr i)
                        (dotimes (j (length ss-exprs))
                          (push (nth j ss-exprs) s-expr i)
                          (inc 'i)))
                      (begin
                        (nth-set i s-expr ss-exprs)
                        (inc 'i)))))
                 (true
                   (nth-set i s-expr (qq-eval ss-expr))
                   (inc 'i)))
              (begin
                (inc 'i)
                s-expr))))
           s-expr)
      s-expr))


The following demonstrates the use of qq and qq-eval.

Code: Select all


  ;; Abbreviation for lambda or fn

  (define-macro (\ )
    (eval (qq-eval '(lambda (uq (first (args))) (uq@ (rest (args)))))))


  ;; Abbreviation for define

  (define-macro (: _var-or-fn _value)
    (if (list? _var-or-fn)
      (eval (qq-eval '(define (uq _var-or-fn) (uq@ (rest (args))))))
      (eval (qq (set _var-or-fn (uq _value))))))


Notice that qq is not used whenever (args)
appears in the expression being quasiquoted.

I'm hoping this makes writing macros more
convenient in newLisp.

Warning: I've only briefly tested this.

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

>>>
;; Since qq is a macro you can't use (args) within.
>>>

its is the other way around macros *can* use (args) normal functions *can not*:

(define-macro (foo) (println (args)))

(foo 1 2 3) => (1 2 3)

(define (foo) (println (args)))

(foo 1 2 3) => ()

Lutz

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

Consider also using 'ref' for looking up 'uq' or 'uq@' expressions. This is how a qq-macro could look like for just handling the unquoting of uq:

Code: Select all

(define-macro (qq s-exp)
  (while  (set 'idx (chop (ref 'uq s-exp)))
      (set 'qx (pop s-exp idx))
      (push (eval (first (rest qx))) s-exp idx))
  s-exp)

;; now use it
(set 'x 'hello)

(qq ( (uq (+ 1 2)) ((uq (+ 3 4)) (uq x)))) => (3 (7 hello))

;; something similar could be done for 'uq@'
'ref' returns the index positions of an expresssion found in a nested list in an index-list, which can be used directly in 'pop' or 'push' which can take index lists. 'pop' and 'push' are inverse of each other. The same index-list used to pop something can be used to push something else back into the same position.

Lutz

jsmall
Posts: 26
Joined: Mon Sep 20, 2004 1:44 am

quasiquote and ref

Post by jsmall »

I've been working on the uq and uq@ using your code example:

Code: Select all


(define-macro (qq s-exp) 
  (while  (set 'idx (chop (ref 'uq s-exp))) 
      (set 'qx (pop s-exp idx)) 
      (push (eval (first (rest qx))) s-exp idx)) 
  s-exp) 

;; now use it 
(set 'x 'hello) 

(qq ( (uq (+ 1 2)) ((uq (+ 3 4)) (uq x)))) => (3 (7 hello)) 

;; something similar could be done for 'uq@' 


1. It would be nice if "ref" had a version that took a predicate, e.g.

Code: Select all


     (ref? (lambda (s-expr) (or (= 'uq s-expr) (= 'uq@ s-expr)))
            s-exp)

and returned the ref path along with the value returned by
the predicate.

2. Also if the continuation bookmark could be captured and
returned as well so that the depth first? search could continue
from where it left off that would also be nice.

Essentially my longer version was taking this approach (1 & 2) but
the size and speed advantage of your approach is obvious.

Locked