Infix.lsp as macro

Started by hds1, June 27, 2017, 12:01:03 AM

Previous topic - Next topic

hds1

Hi,

is it possible to transform the infix.lsp to a "true" macro i.e. doing the work at compile time ?

Or do i miss a critical point there ?

Calling "eval" during runtime is supposed to be expensive (at least in other lisps). Not sure how newlisp handles eval.

Reason for asking is that i redo some of the quaternion calculus as well as geographic math scripts.



i.e.

(INFIX:xlate "εk2 = aekb1 - aejbi + aeibj + aebk  + akbe  - ajbei  + aibej  + a1bek")

--> (setq εk2 (add (add (sub (add (add (add (sub aekb1 aejbi) aeibj) aebk) akbe) ajbei)

   aibej) a1bek))

(INFIX:xlate "e3Xe4_x = sin(y3 - y4) * sin((x3 + x4) / 2) * cos((x3 - x4) / 2) - sin(y3 + y4) * cos((x3 + x4) / 2) * sin((x3 - x4) / 2)")

--> (setq e3Xe4_x (sub (mul (mul (sin (sub y3 y4)) (sin (div (add x3 x4) 2))) (cos (div (sub x3 x4) 2)))



I still can't wrap my mind around the lisp math syntax ... old school i fear ...

rrq

#1
You may do this kind of thing in two steps. Firstly, you define a macro, e.g. > (macro (mix) nil)
(lambda-macro () (expand 'nil))
Thereafter you redefine it to perform the "xlate" call the way you want it, e.g. > (constant 'mix (lambda-macro () (INFIX:xlate (join (map string (args)) " "))))
(lambda-macro () (INFIX:xlate (join (map string (args)) " ")))

Now you can use this in new definitions and expressions with "read-time" xlate-ion. E.g.,
> (define (foo a b) (mix a +  b))
(lambda (a b) (add a b))
> '(mix 4 * 5 + sin(34) * 8 )
(add (mul 4 5) (mul (sin 34) 8))
> (mix 4 * 5 + sin(34) * 8 )
24.23266148896019

Of course, you might want to name it something else than 'mix.

hds1

#2
thanks a ton. I must admit that i would never ever thought of a redefiniton.

Can you explain why the macro becomes "executable" due to the redefiniton ?

rrq

#3
Well, being or not being a macro is, I believe, some flag attached to the symbol, which is set by the "(macro ..)" term. That term also wraps the given "body" into an "expand" term, as is typically useful for these kinds of macros. But not in this case, where you want the xlate-ion to be invoked at read time.



The "(constant ...)" term simply attaches a new definition to the symbol without messing with the flag, and thus redefines it. http://www.newlisp.org/downloads/newlisp_manual.html#macro">The manual has some discussion about this point.

hds1

#4
Exactly what is needed. Thx.

A minor setback is that infix.lsp does not handle "-" with one argument.

Math code is much clearer now.

Proof of expansion during read time attached.



(load "infix.lsp")

(macro (mix) nil)
(constant 'mix (lambda-macro ()
(INFIX:xlate (join (map string (args)) " "))))

(define (quatmul q1 q2)
  (let ((x1 (nth 0 q1)) (y1 (nth 1 q1)) (z1 (nth 2 q1)) (w1 (nth 3 q1))
(x2 (nth 0 q2)) (y2 (nth 1 q2)) (z2 (nth 2 q2)) (w2 (nth 3 q2)))
    (mix w = 0 - x1 * x2 - y1 * y2 - z1 * z2 + w1 * w2)
    (mix x =     x1 * w2 + y1 * z2 - z1 * y2 + w1 * x2)
    (mix y = 0 - x1 * z2 + y1 * w2 + z1 * x2 + w1 * y2)
    (mix z =     x1 * y2 - y1 * x2 + z1 * w2 + w1 * z2)))

(quatmul '(1 2 3 4) '(-9 -4 4 4)) --> Should be 42
(string (source 'quatmul))

==>
(define (quatmul q1 q2)
(let ((x1 (nth 0 q1)) (y1 (nth 1 q1)) (z1 (nth 2 q1)) (w1 (nth 3 q1))
       (x2 (nth 0 q2)) (y2 (nth 1 q2)) (z2 (nth 2 q2)) (w2 (nth 3 q2)))
(setq w (add (sub (sub (sub 0 (mul x1 x2)) (mul y1 y2)) (mul z1 z2)) (mul w1 w2)))
(setq x (add (sub (add (mul x1 w2) (mul y1 z2)) (mul z1 y2)) (mul w1 x2)))
(setq y (add (add (add (mul (sub 0 x1) z2) (mul y1 w2)) (mul z1 x2)) (mul w1 y2)))
(setq z (add (add (sub (mul x1 y2) (mul y1 x2)) (mul z1 w2)) (mul w1 z2)))))