rational library

Started by eddier, September 22, 2004, 02:32:10 PM

Previous topic - Next topic

eddier

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

Lutz

#1
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)

Lutz

#2
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

eddier

#3
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

Lutz

#4
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

Lutz

#5
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

eddier

#6
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

Lutz

#7
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