I'm not a FOOPer, but I'd like to throw out a few comments for discussion, but be warned that what I'm going to cover does NOT improve essentially on what cormullion just wrote -- it just complements it.
Here's the setup, which is slightly different but essentially the same as yours, refrainrence.
Code: Select all
(define (Class:Class) (cons (context) (args)))
(define pi (mul 2 (acos 0)))
(new Class 'Circle)
(define (Circle:radius) (self 3))
(define (Circle:circumference) (mul 2 pi (Circle:radius)))
(define (Circle:area) (mul pi (pow (Circle:radius) 2)))
(Notice that I defined a method,
radius, which is just an accessor. It makes some of the other code easier to read.)
If you want to call a bunch of functions (methods, in this case) on an object, but do it in the functional way (warning: FP is a minority cult on the newLISP forum :), you would call a higher-order function, like
juxt.
Here is a discussion on it, but basically it is defined like this:
Code: Select all
(define (juxt)
(letex (_funcs (args))
(lambda (x)
(map (lambda (f) (f x)) '_funcs))))
and used like this:
Code: Select all
(define (mulby3 x) (mul x 3))
(define (divby3 x) (div x 3))
((juxt mulby3 divby3) 9)
;; => (27 3)
But
juxt will fail miserably, when you use it for your Circle example. For instance, none of these calls work:
Code: Select all
((juxt :radius :area :circumference) mycircle)
((juxt radius area circumference) mycircle)
((juxt Circle:radius Circle:area Circle:circumference) mycircle)
They don't work because methods are invoked differently from regular functions. The colon operator does the dispatching work for you behind the scenes. So if you want to use something like
juxt, you'd only need to write a version of it that handles these methods. Here is a version I wrote, and I just called it by a different name
juxtm.
Code: Select all
(define-macro (juxtm)
(letex (_meths (args))
(lambda (obj)
(letex (_calls
(map (lambda (m) (list ': m obj)) '_meths))
(map eval '_calls)))))
(Notice the
eval in there, just as in cormullion's loop.)
Now, it works as expected.
Code: Select all
(setf mycircle (Circle 1 2 10))
(:radius mycircle)
(:area mycircle)
(:circumference mycircle)
((juxtm radius area circumference) mycircle)
yields
Code: Select all
> (Circle 1 2 10)
> 10
> 314.1592654
> 62.83185307
> (10 314.1592654 62.83185307)
(λx. x x) (λx. x x)