user2553444
user2553444

Reputation: 41

Lisp: rudimentary object-oriented counter

I have to program an object-oriented counter. First the function make-object should instantiate the objects a and b with internal state 0. Then the 'methods' :inc, :dec and :res (increase, decrease, reset) are called. It should look like this:

> (setq a (make-object) b (make-object))
...
> (funcall a :inc)
1
> (funcall a :inc)
2
> (funcall a :res)
0
> (funcall a :dec)
-1
> (funcall b :inc)
1

My solution so far looks like this:

(defun make-object ()
  (let ((counter 0))
    (list #'(lambda () (incf counter))
          #'(lambda () (setf counter 0))
          #'(lambda () (decf counter)))))

With

(setq a (make-object) b (make-object))

I can instantiate a and b and the methods are called with

(funcall (first a))
(funcall (second b))
(funcall (third a))

I tried the following to call the methods with ":inc" instead of "first":

(defun myfuncall (var fun) 
  (funcall ((cond ((equal fun ":inc") first) 
                  ((equal fun ":res") second) 
                  ((equal fun ":dec") third)) 
            var)))

but there's the error

While compiling MYFUNCALL :
In the form (#1=(COND ((EQUAL FUN ":inc") FIRST)
                      ((EQUAL FUN ":res") SECOND)
                      ((EQUAL FUN ":dec") THIRD))
             VAR), #1# is not a symbol or lambda expression.
   [Condition of type CCL::COMPILE-TIME-PROGRAM-ERROR]

Can anyone help me please? How do I make funcall do the right thing for me?


Found the solution.

(defun make-object () 
  (let ((count 0))
    (lambda (msg)
      (case msg
        ((:inc) (incf count))
        ((:dec) (decf count))
        ((:res) (setq count 0))))))

This does what I wanted.

Upvotes: 4

Views: 175

Answers (1)

Rainer Joswig
Rainer Joswig

Reputation: 139251

That's almost working.

(defun myfuncall (var fun) 
  (funcall ((cond ((equal fun ":inc") first) 
                  ((equal fun ":res") second) 
                  ((equal fun ":dec") third)) 
            var)))

There is an extra ( ... ) around the COND and the var form. You need to remove that.

Also first (etc) would be a variable reference. You need to call (first var).

Once you got that working, you may want to write your code differently. What if MAKE-OBJECT would return a single function and not a list of three functions. How could that work?

Next problem

((equal fun ":inc") 'first var)

Above makes no sense. You want to call the function FIRST on the result of var. This then would return a function, which then gets called via FUNCALL.

Upvotes: 3

Related Questions