Back
extend (clj)
(source)function
(extend atype & proto+mmaps)
Implementations of protocol methods can be provided using the extend construct:
(extend AType
AProtocol
{:foo an-existing-fn
:bar (fn [a b] ...)
:baz (fn ([a]...) ([a b] ...)...)}
BProtocol
{...}
...)
extend takes a type/class (or interface, see below), and one or more
protocol + method map pairs. It will extend the polymorphism of the
protocol's methods to call the supplied methods when an AType is
provided as the first argument.
Method maps are maps of the keyword-ized method names to ordinary
fns. This facilitates easy reuse of existing fns and fn maps, for
code reuse/mixins without derivation or composition. You can extend
an interface to a protocol. This is primarily to facilitate interop
with the host (e.g. Java) but opens the door to incidental multiple
inheritance of implementation since a class can inherit from more
than one interface, both of which extend the protocol. It is TBD how
to specify which impl to use. You can extend a protocol on nil.
If you are supplying the definitions explicitly (i.e. not reusing
exsting functions or mixin maps), you may find it more convenient to
use the extend-type or extend-protocol macros.
Note that multiple independent extend clauses can exist for the same
type, not all protocols need be defined in a single extend call.
See also:
extends?, satisfies?, extenders
Examples
viebel/klipse
(ns clojure.core.rrb-vector.interop
(:require [clojure.core.rrb-vector.protocols
:refer [PSliceableVector -slicev
PSpliceableVector -splicev]]
[clojure.core.rrb-vector.rrbt :refer [-as-rrbt]]))
(extend-protocol PSliceableVector
cljs.core/PersistentVector
(-slicev [v start end]
(-slicev (-as-rrbt v) start end))
(extend-protocol PSpliceableVector
cljs.core/PersistentVector
(-splicev [v1 v2]
(-splicev (-as-rrbt v1) v2))
thheller/shadow-cljs
(ns shadow.remote.runtime.cljs.js-builtins
(:require
[goog.object :as gobj]
[clojure.core.protocols :as p]))
(extend-protocol p/Datafiable
;; FIXME: this is kind of a bad idea
;; can't do this for all objects, since none of the CLJS types implement this
;; protocol either. the protocol dispatch will end up using object
;; FIXME: this could detect CLJS types to some extent
;; or should it just implement the protocols for the types?
object
(datafy [o]
(if-not (identical? (.-__proto__ o) js/Object.prototype)
o
(with-meta
(->> (gobj/getKeys o)
(reduce
(fn [m key]
(assoc! m key (gobj/get o key)))
(transient {}))
(persistent!))
jonase/eastwood
(ns testcases.unusednss3
(:require [clojure.core.protocols :as protocols]
[clojure.core.reducers :as reducers]
[clojure.data :as data]
[clojure.java.io :as io]
[clojure.reflect :as reflect]))
(extend String
protocols/IKVReduce
{:kv-reduce (fn [amap f init] nil)})
(extend-protocol reducers/CollFold
String
(coll-fold [coll n combinef reducef] nil))
(extend-type String
data/EqualityPartition
(equality-partition [x] nil))
mikera/core.matrix
Indexes are intended to be used to specify elements, ranges or sub-arrays of core.matrix arrays.
As such they can be considered as a 1D vector of integer values."
(:require [clojure.core.matrix.protocols :as mp]
[clojure.core.matrix.macros :refer [error]])
(:import [clojure.lang IPersistentVector]))
(extend-protocol mp/PIndexImplementation
(Class/forName "[J")
(index? [m]
true)
(index-to-longs [m]
m)
(index-to-ints [m]
(int-array m))
(index-from-longs [m xs]
xs)
(index-from-ints [m xs]
(long-array xs))
(index-coerce [m a]
(mp/index-to-longs a)))
(extend-protocol mp/PIndexImplementation
(Class/forName "[I")
(index? [m]
true)
(index-to-longs [m]
(long-array m))
(index-to-ints [m]
m)
(index-from-longs [m xs]
(int-array xs))
(index-from-ints [m xs]
xs)
(index-coerce [m a]
(mp/index-to-ints a)))
(extend-protocol mp/PIndexImplementation
IPersistentVector
(index? [m]
(every? integer? m))
(index-to-longs [m]
(long-array m))
(index-to-ints [m]
(int-array m))
(index-from-longs [m xs]
(vec xs))
(index-from-ints [m xs]
(vec xs))
(index-coerce [m a]
(cond
(mp/index? a)
(mp/persistent-vector-coerce a)
(== 1 (long (mp/dimensionality a)))
(vec (mp/index-to-longs a))
:else
(error "Can't make a 1D index from array of shape " (mp/get-shape a)))))
mikera/core.matrix
WARNING: because they lack efficient indexed access, sequences will perform badly for most
array operations. In general they should be converted to other implementations before use."
(:require [clojure.core.matrix.protocols :as mp]
[clojure.core.matrix.implementations :as imp]
#?(:clj [clojure.core.matrix.macros :refer [scalar-coerce error]]))
#?(:clj (:import [clojure.lang ISeq])
:cljs (:require-macros [clojure.core.matrix.macros :refer [scalar-coerce error]])))
(extend-protocol mp/PImplementation
ISeq
(implementation-key [m] :sequence)
(meta-info [m]
{:doc "Core.matrix implementation for Clojure ISeq objects"})
(new-vector [m length]
(mp/new-vector [] length))
(new-matrix [m rows columns]
(mp/new-matrix [] rows columns))
(new-matrix-nd [m dims]
(mp/new-matrix-nd [] dims))
(construct-matrix [m data]
(mp/coerce-param [] data))
(supports-dimensionality? [m dims]
true))
(extend-protocol mp/PIndexedAccess
ISeq
(get-1d [m x]
(scalar-coerce (nth m x)))
(get-2d [m x y]
(let [row (nth m x)]
(mp/get-1d row y)))
(get-nd [m indexes]
(if-let [indexes (seq indexes)]
(if-let [next-indexes (next indexes)]
(let [mv (nth m (first indexes))]
(mp/get-nd mv next-indexes))
(nth m (first indexes)))
m ;; TODO: figure out if this is a good return value? should it be an error?
)))
(extend-protocol mp/PIndexedSetting
ISeq
(set-1d [m row v]
(mp/set-1d (mp/convert-to-nested-vectors m) row v))
(set-2d [m row column v]
(mp/set-2d (mp/convert-to-nested-vectors m) row column v))
(set-nd [m indexes v]
(mp/set-nd (mp/convert-to-nested-vectors m) indexes v))
(is-mutable? [m]
false))
(extend-protocol mp/PBroadcast
ISeq
(broadcast [m new-shape]
(mp/broadcast (mp/convert-to-nested-vectors m) new-shape)))
(extend-protocol mp/PBroadcastLike
ISeq
(broadcast-like [m a]
(mp/broadcast (mp/convert-to-nested-vectors a) (mp/get-shape m))))
(extend-protocol mp/PSliceView
ISeq
(get-major-slice-view [m i]
(nth m i)))
(extend-protocol mp/PSliceSeq
ISeq
(get-major-slice-seq [m] (vec m)))
(extend-protocol mp/PMatrixRows
ISeq
(get-rows [m]
(vec m)))
(extend-protocol mp/PMatrixColumns
ISeq
(get-columns [m]
(let [m (mp/coerce-param [] m)]
(mp/get-columns m))))
(extend-protocol mp/PSliceSeq2
ISeq
(get-slice-seq [m dimension]
(let [ldimension (long dimension)]
(cond
(== ldimension 0) (mp/get-major-slice-seq m)
(< ldimension 0) (error "Can't get slices of a negative dimension: " dimension)
:else (mapv #(mp/get-slice m dimension %) (range (mp/dimension-count m dimension)))))))
(extend-protocol mp/PConversion
ISeq
(convert-to-nested-vectors [m]
(if (> (mp/dimensionality (first m)) 0)
(mapv mp/convert-to-nested-vectors m)
(vec m))))
(extend-protocol mp/PDimensionInfo
ISeq
(dimensionality [m]
(inc (mp/dimensionality (first m))))
(is-vector? [m]
(== 0 (mp/dimensionality (first m))))
(is-scalar? [m]
false)
(get-shape [m]
#?(:cljs (js/console.log (str "shape of seq: " m)))
(cons (count m) (mp/get-shape (first m))))
(dimension-count [m x]
(if (== x 0)
(count m)
(mp/dimension-count (first m) (dec x)))))
(extend-protocol mp/PFunctionalOperations
ISeq
(element-seq [m]
(if (== 0 (long (mp/dimensionality (first m))))
m ;; handle 1D case, just return this sequence unchanged
(mapcat mp/element-seq m)))
(element-map
([m f]
(mapv #(mp/element-map % f) m))
([m f a]
(let [[m a] (mp/broadcast-compatible m a)]
(mapv #(mp/element-map % f %2) m (mp/get-major-slice-seq a))))
([m f a more]
(let [[m a & more] (apply mp/broadcast-compatible m a more)] ; FIXME
(mapv #(mp/element-map % f %2 %3) m (mp/get-major-slice-seq a) (map mp/get-major-slice-seq more)))))
(element-map!
([m f]
(error "Sequence arrays are not mutable!"))
([m f a]
(error "Sequence arrays are not mutable!"))
([m f a more]
(error "Sequence arrays are not mutable!")))
(element-reduce
([m f]
(reduce f (mapcat mp/element-seq m)))
([m f init]
(reduce f init (mapcat mp/element-seq m)))))
(extend-protocol mp/PMapIndexed
ISeq
(element-map-indexed
([ms f]
(mapv (fn [i m] (mp/element-map-indexed m #(apply f (cons i %1) %&)))
(range (count ms)) ms))
([ms f as]
(let [[ms as] (mp/broadcast-compatible ms as)]
(mapv (fn [i m a]
(mp/element-map-indexed m #(apply f (cons i %1) %&) a))
(range (count ms)) ms (mp/get-major-slice-seq as))))
([ms f as more]
(let [[ms as & more] (apply mp/broadcast-compatible ms as more)] ; FIXME
(mapv (fn [i m a & mr]
(mp/element-map-indexed m #(apply f (cons i %1) %&) a mr))
(range (count ms)) ms
(mp/get-major-slice-seq as)
(map mp/get-major-slice-seq more)))))
(element-map-indexed!
([m f]
(error "Sequence arrays are not mutable!"))
([m f a]
(error "Sequence arrays are not mutable!"))
([m f a more]
(error "Sequence arrays are not mutable!"))))