Смесване на definterface и defprotocol

Опитвам се да внедря интерфейс, представящ аритметични изрази. Интерфейсът ще се използва от страна на java, но цялата логика е на clojure.

като:

(defprotocol ExtendsExpression
  (toTree [this]))

(extend-type String
  ExtendsExpression
  (toTree [this] (symbol this)))

(extend-type Number
  ExtendsExpression
  (toTree [this] this))

(definterface Expression
  (toTree []))

(defrecord Expression1 [^String oper arg]
  Expression
  (toTree [this]
    (list (symbol oper) (toTree arg))))


(defrecord Expression2 [^String oper arg1 arg2]
  Expression
  (toTree [this]
    (list (symbol oper) (toTree arg1) (toTree arg2))))

(defrecord Expression3 [^String oper arg1 arg2 arg3]
  Expression
  (toTree [this]
    (list (symbol oper) (toTree arg1) (toTree arg2) (toTree arg3))))

Опитвам се да го използвам като:

(toTree (Expression3. "+" "a" "b" (Expression2. "*" "c" "d")))

но получавам:

IllegalArgumentException No implementation of method: :toTree of protocol: #'user/ExtendsExpression found for class: user.Expression3  clojure.core/-cache-protocol-fn (core_deftype.clj:541)

Защо clojure се опитва да извика toTree на ExtendsExpression за Expression3? Очаквам, че за Expression3 ще извика метода toTree на интерфейса Expression.


person Lambder    schedule 16.08.2013    source източник


Отговори (1)


Добре, разбрах ;)

(defprotocol ExtendsExpression
  (to-tree [this]))

(extend-type String
  ExtendsExpression
  (to-tree [this] (symbol this)))

(extend-type Number
  ExtendsExpression
  (to-tree [this] this))

(definterface Expression
  (toTree []))

(defrecord Expression1 [^String oper arg]
  ExtendsExpression
  (to-tree [this]
    (list (symbol oper) (to-tree arg)))
  Expression
  (toTree [this] (to-tree this)))


(defrecord Expression2 [^String oper arg1 arg2]
  ExtendsExpression
  (to-tree [this]
    (list (symbol oper) (to-tree arg1) (to-tree arg2)))
  Expression
  (toTree [this] (to-tree this)))

(defrecord Expression3 [^String oper arg1 arg2 arg3]
  ExtendsExpression
  (to-tree [this]
    (list (symbol oper) (to-tree arg1) (to-tree arg2) (to-tree arg3)))
  Expression
  (toTree [this] (to-tree this)))

(to-tree (Expression3. "+" "a" "b" (Expression2. "*" "c" "d"))) ;=> (+ a b (* c d))

и записите имплементират Expression интерфейс, така че мога лесно да ги извикам от java:

(.toTree (Expression3. "+" "a" "b" (Expression2. "*" "c" "d"))) ;=> (+ a b (* c d))

само за да проверите какви интерфейси изпълнява Expression3:

 (-> Expression3 clojure.reflect/reflect :bases pprint)
#{clojure.lang.IHashEq java.io.Serializable clojure.lang.IKeywordLookup
  clojure.lang.IPersistentMap clojure.lang.IRecord java.lang.Object
  user.ExtendsExpression clojure.lang.IObj clojure.lang.ILookup
  user.Expression java.util.Map}
person Lambder    schedule 16.08.2013