newLISP Fan Club

Forum => newLISP in the real world => Topic started by: eddier on September 22, 2004, 02:32:10 PM

Title: rational library
Post by: eddier on September 22, 2004, 02:32:10 PM
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
Title:
Post by: Lutz on September 22, 2004, 03:19:33 PM
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)
Title:
Post by: Lutz on September 22, 2004, 03:29:01 PM
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
Title:
Post by: eddier on September 23, 2004, 05:46:59 AM
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
Title:
Post by: Lutz on September 23, 2004, 04:39:41 PM
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
Title:
Post by: Lutz on September 24, 2004, 06:37:16 AM
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
Title:
Post by: eddier on September 24, 2004, 06:58:14 AM
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
Title:
Post by: Lutz on September 24, 2004, 09:54:25 AM
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