I'm having trouble with some macros.
(context 'Q)
;; '(2) means 2/1, '(1 2) means 1/2, and (2 2 3) means 2 2/3
;; all functions below will work with the above types
;; (Q:neg '(1 2) => (-1 2)
;; (Q:reciprical '(-2 3) => (-3 2)
;; (Q:+ '(1 2) '(1 3)) => (5 6)
;; (Q:- '(1 2) '(1 3)) => (1 6)
;; (Q:* '(1 2) '(1 3)) => (1 6)
;; (Q:/ '(1 2) '(1 3)) => (3 2)
(define (gcd_ a b)
;; used to reduce fractions
(let (r (% b a)) (if (= r 0) a (gcd_ r a))))
(define (frac-form a b)
;; reduce and fix negatives so that -a/-b => a/b, a/-b => -a/b
(if
(= a 0)
'(0 1)
(= b 0)
(throw "rational-number-error")
(let (dd (gcd_ a b))
(let (a (/ a dd) b (/ b dd))
(if
(and (< a 0) (< b 0))
(map abs (list a b))
(and (>= a 0) (< b 0))
(list (- 0 a) (abs b))
(list a b))))))
(define (improper L)
;; convert a -> a/1 and a b/c -> (c*a+b)/c
(map set '(n d)
(if
(= (length L) 1)
(list (first L) 1)
(= (length L) 2)
L
(= (length L) 3)
(list (+ (nth 1 L) (* (first L) (last L))) (last L))))
(frac-form n d))
(define (neg A)
(map set '(n d) (improper A))
(frac-form (- 0 n) d))
(define (add_q A B)
(map set '(n0 d0 n1 d1) (append (improper A) (improper B)))
(let (n (+ (* n0 d1) (* n1 d0)) d (* d0 d1))
(if (frac-form n d))))
(define (sub_q A B)
(add_q A (neg B)))
(define (mul_q A B)
(map set '(n0 d0 n1 d1) (append (improper A) (improper B)))
(frac-form (* n0 n1) (* d0 d1)))
(define (reciprical A)
(frac-form (last A) (first A)))
(define (div_q A B)
(mul_q A (reciprical B)))
(define (->string A)
(if (= (last A) 1)
(string (first A))
(string (first A) "/" (last A))))
(constant 'Q:+ add_q)
(constant 'Q:- sub_q)
(constant 'Q:* mul_q)
(constant 'Q:/ div_q)
(context 'MAIN)
The functions work just fine until I add something like
(define-macro (qadd) (apply add_q (args) 2))
and then I get the error
list expected : (if (= (length Q:L) 1)
(list (first Q:L) 1)
(= (length Q:L) 2) Q:L
(= (length Q:L) 3)
(list (+ (nth 1 Q:L) (* (first Q:L) (last Q:L))) (last Q:L)))
called from user defined function improper
Why?
Eddie
The local overwritten versions of the operators =,-,*,/ must exist before the code after gets translated by newLISP. If not all =,-,*,/ will be bound to the MAIN versions during translation of the functions. This is the correct way to the overloading of local +,-,*,/
(context 'Q)
(constant 'Q:+) ; create local version of +
...
(define (add_q)
...
...
)
...
...
(constant '+ add_q) ; can ommit the Q prefix because '+' refers to local '+'
(context 'MAIN)
Here is a complete example:
;; demonstrate overloading of operators inside a context
;;
;; (Q:foo 4 4) => 6
(context 'Q)
(constant 'Q:+) ; create local version of +
(define (greedy-add x y)
(add x (div y 2)))
(define (foo x y)
(+ x y))
(constant '+ greedy-add)
(context 'MAIN)
or a short version:
(context 'Q)
(constant 'Q:+
(lambda (x y) (add x (div y 2))))
(define (foo x y)
(+ x y))
(context 'MAIN)
Lutz
Actually the overloading worked and is not the problem. I can do without overloading for right now. The real problem is with
(define-macro (qadd)
(apply add_q (args) 2))
still gives the same error.
(Q:add_q '(1 2) '(3 4))
works great with two arguments. When I define a macro to work on multiple arguments (above) I get the list error.
Eddie
This will take some time for me to explore, meanwhile try to put some 'println' or use (debug (Q:add_q '(1 2) '(3 4))) to explore what is happening.
You don't need newlisp-tk to used (debug ...) it works fine in the console. At each step you can evaulate lisp-expressions to see what is going on.
Lutz
It works perfectly put you have to call the macro differently, becaus it does not evaluate it's arguments:
(define-macro (qadd) (apply add_q (args) 2)) ;; added in context Q
sould be called:
(Q:qadd (1 2) (3 4) (4 5)) => (25 12)
Try this:
(define-macro (qadd) (apply add_q (args) 2))
(try '(1 2) '(3 4)) => ('(1 2) '(3 4))
Lutz
Thanks Lutz, I just figured that out as well. I'm making changes in the code to make it more efficient and work with intgers as well.
(Q:+ 2 (1 2) (1 3) (1 1 2)) => (13 3)
Eddie
When I looked at your 'rational library' code more thoroughly, I realized, that overloading was done correctly in your case, as you wanted to use the native +,-,*,/ thrughout your definitions.
A potential danger exists when loading the Q context twice. Then all definitions would come out wrong the second time using the overloaded +,-,*,/. There is no possibility currently to get rid of constant symbols, you can only redefine them with 'constant', but not 'delete' them.
The only thing you could do to protect against it, is for every function definition using =,-,*,/ inside:
(if (not foo) (define (foo x y z)
...
...
))
Lutz