Page 1 of 1

rational library

Posted: Wed Sep 22, 2004 9:32 pm
by eddier
I'm having trouble with some macros.

Code: Select all

(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

Code: Select all

(define-macro (qadd) (apply add_q (args) 2))
and then I get the error

Code: Select all

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

Posted: Wed Sep 22, 2004 10:19 pm
by Lutz
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 +,-,*,/

Code: Select all

(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)

Posted: Wed Sep 22, 2004 10:29 pm
by Lutz
Here is a complete example:

Code: Select all

;; 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:

Code: Select all

(context 'Q)

(constant 'Q:+ 
	(lambda (x y)   (add x (div y 2))))

(define (foo x y)
   (+ x y))

(context 'MAIN)
Lutz

Posted: Thu Sep 23, 2004 12:46 pm
by eddier
Actually the overloading worked and is not the problem. I can do without overloading for right now. The real problem is with

Code: Select all

(define-macro (qadd)
 (apply add_q (args) 2))
still gives the same error.

Code: Select all

(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

Posted: Thu Sep 23, 2004 11:39 pm
by Lutz
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

Posted: Fri Sep 24, 2004 1:37 pm
by 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

Posted: Fri Sep 24, 2004 1:58 pm
by eddier
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.

Code: Select all

(Q:+ 2 (1 2) (1 3) (1 1 2)) => (13 3)
Eddie

Posted: Fri Sep 24, 2004 4:54 pm
by Lutz
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