Смешивание 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 of ExtendsExpression для Expression3? Я ожидаю, что для Expression3 он вызовет метод toTree интерфейса Expression.
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}