       (count indexes) [m m] indexes
       (.set m (long-array indexes) v))))
 
-(extend-protocol PMatrixAdd
-  (matrix-add [m a]
-    (.add m m))
-  (matrix-sub [m b]
-    (.add m a)))
-
-(extend-protocol PMatrixMultiply
-  (element-multiply [m a]
-    (.mul m a)))
-
-(extend-protocol PMatrixDivide
-  (element-divide [m a]
-    (.div m a)))
-
+(defmacro with-coerce-param [bindings & body]
+  (assert (= (count bindings) 2))
+  (assert (symbol? (first bindings)))
+  (let [param-sym (first bindings)
+        param-val (second bindings)]
+    `(cond (number? ~param-val)
+           (let [~param-sym (double ~param-val)]
+             ~@body)
+           (instance? NDArray ~param-val)
+           (let [~(vary-meta param-sym assoc :tag `NDArray) ~param-val]
+             ~@body)
+           ; unkown type, we need to coerce it to NDArray
+           :else
+           (let [~(vary-meta param-sym assoc :tag `NDArray)
+                 (mp/coerce-param (gpu.matrix.NDArray/sample) ~param-val)]
+             ~@body))))
+
+(extend-protocol mp/PMatrixAdd
+  NDArray
+  (matrix-add [^NDArray m a]
+    (with-coerce-param [a a] (.add m a)))
+  (matrix-sub [^NDArray m a]
+    (with-coerce-param [a a] (.sub m a))))
+
+(extend-protocol mp/PMatrixMultiply
+  NDArray
+  (element-multiply [^NDArray m a]
+    (with-coerce-param [a a] (.mul m a))))
+
+(extend-protocol mp/PMatrixDivide
+  NDArray
+  (element-divide [^NDArray m a]
+    (with-coerce-param [a a] (.div m a))))
+

        (error (str "Invalid dimension! Expecting dimension to be between inclusive 0 and "
                    (dec ndims) ", but got " dimension-number "instead!"))
        (aget shape dimension-number)))))

(defn- all?
  "returns true if every element in coll (or the mapped version, if 

        (double-array (flatten data))
        ndims
        (long-array shape))))

; assume it is an arbitary implementation
; construct a persistent vector representation of the data
(defmethod construct-matrix :default
  [data]
  (let [vm (mp/construct-matrix [] (m/shape data))]
    (construct-matrix vm)))

(extend-protocol mp/PImplementation
  NDArray
