В более широком смысле этот вопрос касается различных подходов к проблеме выражения . Идея состоит в том, что ваша программа представляет собой комбинацию типа данных и операций над ним. Мы хотим иметь возможность добавлять новые случаи без перекомпиляции старых классов.
Теперь у Haskell есть несколько действительно удивительных решений проблемы с класса типов. В частности - мы можем сделать:
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
member :: (Eq a) => a -> [a] -> Bool
member y [] = False
member y (x:xs) = (x == y) || member y xs
Теперь в Clojure есть multimethods - так вы можете сделать:
(defmulti area :Shape)
(defn rect [wd ht] {:Shape :Rect :wd wd :ht ht})
(defn circle [radius] {:Shape :Circle :radius radius})
(defmethod area :Rect [r]
(* (:wd r) (:ht r)))
(defmethod area :Circle [c]
(* (. Math PI) (* (:radius c) (:radius c))))
(defmethod area :default [x] :oops)
(def r (rect 4 13))
(def c (circle 12))
(area r)
-> 52
(area c)
-> 452.3893421169302
(area {})
-> :oops
Также в Clojure у вас protocols - с помощью которого вы можете:
(defprotocol P
(foo [x])
(bar-me [x] [x y]))
(deftype Foo [a b c]
P
(foo [x] a)
(bar-me [x] b)
(bar-me [x y] (+ c y)))
(bar-me (Foo. 1 2 3) 42)
=> 45
(foo
(let [x 42]
(reify P
(foo [this] 17)
(bar-me [this] x)
(bar-me [this y] x))))
=> 17
Теперь этот человек делает заявку:
Но существуют протоколы и мульти-методы. Они очень мощные, но не столь мощные, как классные классы Haskell. Вы можете ввести что-то вроде typeclass, указав свой контракт в протоколе. Это только отправляет по первому аргументу, тогда как Haskell может отправлять всю подпись, включая возвращаемое значение. Мульти-методы более мощные, чем протоколы, но не такие мощные, как отправка Haskell.
Мой вопрос: Каковы причины того, что протоколы и мультиметоды в Clojure менее эффективны для полиморфизма, чем типы стеков в Haskell?