在静态语言中,我可以replace conditional with polymorphism。
在像erlang这样的语言中,我可以使用模式匹配而不是if else。
我在clojure中可以使用什么?
答案 0 :(得分:9)
模式匹配和多态分派都可用。
两种形式的多态分派是多方法和协议。
leontalbot提供了一个很好的 multimethods 示例,它根据参数的某些特定属性调度到特定的实现(可以是类型,但是它们可以使用不同的调度函数)。换句话说,决定使用哪个实现方法会对参数执行一个函数,并将其与调度表进行比较。
这是另一个例子:
; Declare multimethod:
(defmulti get-length class)
; Provide implementations for concrete types:
(defmethod get-length java.lang.String [str] (.length str))
(defmethod get-length java.lang.Number [num] (.length (str num)))
; Call it for String:
(get-length "Hello") ;=> 5
; Call it for a Number (works because Long is a subtype of Number):
(get-length 1234) ;=> 4
我们在这里使用简单的例子来保持简单,但调度功能可能更有趣。再举一个例子,我们想要根据输入长度选择排序算法:
(defn choose-impl [in]
(cond
(is-sorted? in) :sorted
(< (count in) 10) :bubble
:else :quicksort))
(defmulti my-sort choose-impl)
(defmethod my-sort :sorted [in] in)
(defmethod my-sort :bubble [in] (my-bubble-sort in))
(defmethod my-sort :quicksort [in] (my-quicksort in))
这个是设计的,您可能不会以这种方式实现它,但我希望它是使用不同调度函数的好例子。
协议是另一回事,更像是Java和其他OO语言中已知的接口。您定义了一组形成协议的操作,然后提供各种类型的实现。
; Protocol specification:
(defprotocol my-length (get-length [x]))
; Records can implement protocols:
(defrecord my-constant-record [value]
my-length
(get-length [x] value))
; We can "extend" existing types to support the protocol too:
(extend-protocol my-length
java.lang.String
(get-length [x] (.length x))
java.lang.Long
(get-length [x] (.length (.toString x))))
; Now calling get-length will find the right implementation for each:
(get-length (my-constant-record. 15)) ;=> 15
(get-length "123") ;=> 3
(get-length 1234) ;=> 4
最后,模式匹配适用于非常受欢迎的core.match库:
(doseq [n (range 1 101)]
(println
(match [(mod n 3) (mod n 5)]
[0 0] "FizzBuzz"
[0 _] "Fizz"
[_ 0] "Buzz"
:else n)))
答案 1 :(得分:7)
您想要使用多方法。这是一篇很好的文章,解释了如何使用它们。 http://adambard.com/blog/structured-clojure-protocols-and-multimethods/
(def speed 24)
(defmulti get-speed :type)
(defmethod get-speed :european [_] speed)
(defmethod get-speed :african [_] (+ speed 2))
(defmethod get-speed :norwegian-blue [_] (* speed 1.05))
(get-speed {:type :european})
; => 200