rational library

Q&A's, tips, howto's
Locked
eddier
Posts: 289
Joined: Mon Oct 07, 2002 2:48 pm
Location: Blue Mountain College, MS US

rational library

Post 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

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

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

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

Post 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

eddier
Posts: 289
Joined: Mon Oct 07, 2002 2:48 pm
Location: Blue Mountain College, MS US

Post 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

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

Post 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

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

Post 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

eddier
Posts: 289
Joined: Mon Oct 07, 2002 2:48 pm
Location: Blue Mountain College, MS US

Post 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

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

Post 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

Locked