Clojure реализации мультиметодов / протоколов - PullRequest
1 голос
/ 17 октября 2019

Я новичок в clojure и мне это очень нравится. Сейчас я пытаюсь подняться и использовать больше возможностей языка: мультиметоды и протоколы

Я видел много постов в блоге, документов и вопросов, касающихсяна эту тему, но я все еще не уверен, что я понимаю.

Предположим, у меня есть функция, которая меняет поведение в зависимости от типа входного аргумента. Я могу реализовать функцию либо через multimethod или протокол :

;; Multi
(defmulti foo class)

(defmethod foo java.lang.Double [x]
  "A double (via multimethod)")

(defmethod do-a-thing java.lang.Long [x]
  "A long (via multimethod)")


;; Protocol
(defprotocol Bar 
  (bar [x] "..."))

(extend-protocol Bar 
  java.lang.Double
    (bar [x] "A double (via protocol)")
  java.lang.Long 
    (bar [x] "A long (via protocol)"))

Обе работы, и кажется, что подход протокола предпочтительнее для целей скорости.

Однако я хотел бы реализовать математическую функцию (например, площадь), которая зависит от входного параметра. Один из подходов заключается в использовании case , но я не нахожу его чистым.

Поэтому я попробовал версию multimethod . Это работает как чудо:

(defmulti area (fn [shape & _]
                 shape))

(defmethod area :square
  [_ x]
  (* x x))

(defmethod area :circle
  [_ r]
  (* r r Math/PI))

(defmethod area :triangle
  [_ b h]
  (* 1/2 b h))

Но следующая реализация протокола не работает:

(defprotocol Surface 
  (surface [x] 0.0))

(extend-protocol Surface
  :square
    (surface [x] (* x x))
  :circle
    (surface [r] (* r R Math/PI))
  :triangle
    (surface [b h] (* 1/2 b h)))

Я получаю следующую ошибку:

Execution error (ClassCastException) at user/eval2081 (REPL:1).
class clojure.lang.Keyword cannot be cast to class java.lang.Class (clojure.lang.Keyword is in unnamed module of loader 'bootstrap'; java.lang.Class is in module java.base of loader 'bootstrap')

Myвопросы:

  1. Есть ли способ реализовать эту функцию с протоколами или это проблема multimethod only?

  2. Поддерживают ли протоколы только распознавание на основе type ? Как указано здесь https://stackoverflow.com/a/8074581/1537744?

1 Ответ

4 голосов
/ 17 октября 2019

Вот отличный ресурс по протоколам

Диспетчеризация функций протокола по типу их первого аргумента.

    (defprotocol Area
      (area [this] "Get area of shape"))

    (defrecord Square [x]
      Area
      (area [this] (* (:x this) (:x this))))

    (defrecord Circle [r]
      Area
      (area [this] (* (:r this) (:r this) Math/PI)))

    (defrecord Triangle [b h]
      Area
      (area [this] (* 1/2 (:b this) (:h this))))

    (map area [(Square. 10) (Circle. 10) (Triangle. 10 15)])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...