Clojure multimethod dispath problem
I have those two sources:
(ns odo.IComplex)
(gen-interface
:name odo.IComplex
:methods [
[getReal [] Double]
[getImag [] Double]
[getAbs [] Double]
[getArg [] Double]
[setReal [Double] void]
[setImag [Double] void]
[setAbs [Double] void]
[setArg [Double] void]])
(defprotocol PolarComplex
(abs [this] [this value])
(arg [this] [this value]))
(defmulti polar-complex (fn([record abs arg] (class record))))
and
(ns odo.Complex
(:gen-class
:init init
:state state
:implements [odo.IComplex])
(:use odo.IComplex))
(defrecord State [^Double imag ^Double real]
Object (toString [self]
(str real (if (>= imag 0) " + " " - " ) (Math/abs imag) "j"
" : " (abs self) " * exp[ " (arg self) " ]"))
PolarComplex (abs [self] (Math/sqrt (+ (* real real) (* imag imag))))
(abs [self value] (polar-complex self value (arg self)))
(arg [self] (Math/atan2 real imag))
(arg [self value] (polar-complex self (abs self) value)))
(defmethod polar-complex PolarComplex [num abs arg]
(assoc num :real (* abs (Math/cos arg)) :imag (* abs (Math/sin arg))))
(defn -init [] [[] (atom (State. 0. 0.))])
(defn -getImag [self] (:imag @(.state self)))
(defn -getReal [self] (:real @(.state self)))
(defn -getAbs [self] (abs @(.state self)))
(defn -getArg [self] (arg @(.state self)))
(defn -setImag [self value] (swap! (.state self) assoc :imag value))
(defn -setReal [self value] (swap! (.state self) assoc :real value))
(defn -setAbs [self value] (swap! (.state self) abs value))
(defn -setArg [self value] (swap! (.state self) arg value))
(defn -toString [self] (str @(.state se开发者_C百科lf)))
and I'm ensured that (isa? odo.Complex.State odo.IComplex.PolarComplex)
is true
but when I execute
(doto (odo.Complex.)
(.setArg (/ Math/PI 4.)) (.setAbs (Math/sqrt 2)) (println) )
I get
java.lang.IllegalArgumentException: No method in multimethod 'polar-complex' for dispatch value: class odo.Complex.State
Can you tell me why?
I have discovered that in context of its definition var PolarComplex
is bound to map containing information about protocol, not to Class. So correct implementation of multimethod will be
(defmethod polar-complex (:on-interface PolarComplex) [num abs arg]
(assoc num :real (* abs (Math/cos arg)) :imag (* abs (Math/sin arg))))
or
(defmethod polar-complex odo.IComplex.PolarComplex [num abs arg]
(assoc num :real (* abs (Math/cos arg)) :imag (* abs (Math/sin arg))))
精彩评论