Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

For educational purposes I've tried to implement a simple algebraic OOP example using CLOS. The functionality is as far as I can say as it is supposed to be. The intended approach was to implement a simple example of ideomatic OOP polymorphism. For a greater learning experience I've wanted to show the code to get suggestions, critic and so on.

;; main node class, most general
(defclass node ()
  ;; abstract class for nodes
  ((value :initarg :value :reader value)))

(defgeneric evaluate (node)
  (:documentation "the standard evaluation"))


;; node containing an operation, more specific
(defclass op-node (node)
  ;; abstract class for a node containing an operation
  ((left-node  :initform nil :initarg :left-node  :reader left-node)
   (right-node :initform nil :initarg :right-node :reader right-node)))

(defmethod evaluate ((node op-node))
  (apply (value node) 
         (list (evaluate (left-node node))
               (evaluate (right-node node)))))


;; concrete nodes
(defclass add-node (op-node)
  ;; class for addition
  ((value :initform #'+ :reader value)))

(defclass minus-node (op-node)
  ;; class for subtraction
  ((value :initform #'- :reader value)))

(defclass multi-node (op-node)
  ;; class for multiplication
  ((value :initform #'* :reader value)))


(defclass value-node (node)
  ;; class for a node containing a numerical value
  ((value :initarg :value :reader value)))

(defmethod evaluate (value-node)
  (value value-node))


;; 1 + 3
(setf *simple-add* (make-instance 'add-node 
                                  :left-node  (make-instance 'value-node :value 1)
                                  :right-node (make-instance 'value-node :value 3)))

;; 1 * 10
(setf *simple-multi* (make-instance 'multi-node
                                    :left-node  (make-instance 'value-node :value 1)
                                    :right-node (make-instance 'value-node :value 10)))

;; (1 + 3) + (1 * 10)
(setf *advanced-add* (make-instance 'add-node
                                    :left-node *simple-add*
                                    :right-node *simple-multi*))

(evaluate *simple-add*)   ;; => 4
(evaluate *simple-multi*  ;; => 10
(evaluate *advanced-add*) ;; => 14
share|improve this question

2 Answers

up vote 2 down vote accepted
(defmethod evaluate ((node op-node))
  (apply (value node) 
         (list (evaluate (left-node node))
               (evaluate (right-node node)))))

can be written:

(defmethod evaluate ((node op-node))
  (funcall (value node) 
           (evaluate (left-node node))
           (evaluate (right-node node))))

For this example, instead of different subclasses for every binary operation, you could just use a binop class and instantiate it with the respective functions, since they share the same evaluate method, but that depends on what else you want do do with the nodes. (Maybe, for example, you want to have different print-object methods for each of them.)

(Also, using toplevel setfs on unestablished symbols is considered bad style, but I suppose this was just for testing and demonstration purposes. In real code, defparameter or defvar should be used.)

share|improve this answer
Is there any difference between using apply and funcall in this case? Are there cases where one is better usage instead of the other? The binop class hint is very good! I thought of abstracting it more but I wasn't sure how to do it without getting the code too confusing. – beyeran Aug 25 '12 at 7:47
lispworks.com/documentation/HyperSpec/Body/f_funcal.htm: (funcall function arg1 arg2 ...) == (apply function arg1 arg2 ... nil) == (apply function (list arg1 arg2 ...)). So no, there is no difference in this case. Just use whatever is less convoluted. – danlei Aug 25 '12 at 9:38
(defmethod evaluate (value-node)
  (value value-node))

try calling (evaluate 't). Why did that method get called?

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.