【问题标题】:Clojure multimethods/protocols implementationsClojure 多方法/协议实现
【发布时间】:2019-10-17 08:05:48
【问题描述】:

我是 clojure 的新手,我非常喜欢它。现在,我正在尝试加强并使用该语言的更多功能:multimethodsprotocols

我已经看到很多博客文章、文档和问题都涉及到这个主题,但我仍然不确定我是否明白。

假设我有一个函数可以根据输入参数的类型改变行为。我可以通过 multimethodprotocol 来实现该功能:

;; 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')

我的问题是:

  1. 有没有办法用协议实现这个功能,或者这是多方法唯一的问题?

  2. 协议是否仅适用于基于类型的识别?就像这里所说的https://stackoverflow.com/a/8074581/1537744

【问题讨论】:

    标签: clojure


    【解决方案1】:

    这是protocols上的一个很好的资源

    协议函数根据其第一个参数的类型分派。

        (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)])
    

    【讨论】:

      猜你喜欢
      • 2011-12-25
      • 2011-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多