Clojure 中的协议和多方法的多态性不如 Haskell 中的类型类强大的原因是什么? [英] What are the reasons that protocols and multimethods in Clojure are less powerful for polymorphism than typeclasses in Haskell?

查看:20
本文介绍了Clojure 中的协议和多方法的多态性不如 Haskell 中的类型类强大的原因是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更广泛地说,这个问题是关于表达问题的各种方法.这个想法是你的程序是数据类型和对它的操作的组合.我们希望能够在不重新编译旧类的情况下添加新案例.

More broadly this question is about various approaches to the expression problem. The idea is that your program is a combination of a datatype and operations over it. We want to be able to add new cases without recompiling the old classes.

现在 Haskell 有一些非常棒的解决方案来解决表达式问题TypeClass.特别是 - 我们可以:

Now Haskell has some really awesome solutions to the expression problem with the TypeClass. In particular - we can do:

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 - 所以你可以这样做:

Now in Clojure there are multimethods - so you can do:

(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 中,您还有 协议 - 您可以使用它:

Also in Clojure you have protocols - with which you can do:

(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 的类型类强大.您可以通过在协议中指定合同来引入类型类之类的东西.这仅在第一个参数上调度,而 Haskell 可以在整个签名上调度,包括返回值.多方法比协议更强大,但不如 Haskell 的 dispatch 强大.

But, there are protocols and multi-methods. These are very powerful, but not as powerful as Haskell's typeclasses. You can introduce something like a typeclass by specifying your contract in a protocol. This only dispatches on the first argument, whereas Haskell can dispatch on the entire signature, including return value. Multi-methods are more powerful than protocols, but not as powerful as Haskell's dispatch.

我的问题是:Clojure 中的协议和多方法的多态性不如 Haskell 中的类型类强大的原因是什么?

推荐答案

显而易见的是,协议只能在第一个参数上调度,而且只能在第一个参数上调度.这意味着它们大致相当于

Well the obvious one is that protocols can only dispatch on the first and only the first argument. This means they're roughly equivalent to

 class Foo a where
   bar  :: a -> ...
   quux :: a -> ...
   ...

其中 a 必须 是第一个参数.Haskell 的类型类让 a 出现在函数的任何地方.所以协议的表现力很容易低于类型类.

Where a must be the first argument. Haskell's type classes let a appear anywhere in the function. So protocols are easily less expressive than typeclasses.

接下来是多方法.多方法,如果我没记错的话,允许基于所有参数的函数进行调度.这在某些方面看起来比 Haskell 更具表现力,因为您可以以不同的方式分派相同类型的参数.然而,这实际上可以在 Haskell 中完成,通常通过将参数包装在一个 newtype 中进行调度.

Next is multimethods. Multimethods, if I'm not mistaken, allow dispatch based on a function of all the arguments. This looks more expressive in some ways than Haskell, since you can dispatch arguments of the same type differently. However, this can actually be done in Haskell, generally by wrapping the argument in a newtype for dispatching.

据我所知,使用多种方法不能完成的一些事情:

A few things that can't be done with multimethods to my knowledge:

  1. 按退货类型发货
  2. 在类型类的所有类型上存储多态值 forall a.Foo a =>一个

要了解 1. 如何发挥作用,请考虑 Monoid 它有一个值 mempty :: Monoid m =>米.它不是一个函数,用 Clojure 模拟这是不可能的,因为我们没有关于我们期望选择什么方法的任何类型信息.

To see how 1. comes into play, consider Monoid it has a value mempty :: Monoid m => m. It's not a function, and simulating this is impossible with Clojure since we don't have any type information about what method we're expected to choose.

对于 2. 考虑 read :: Read a =>字符串 ->一个.在 Haskell 中,我们实际上可以创建一个类型为 [forall a.读取一个 =>a],我们基本上推迟了计算,现在我们可以运行和重新运行列表的元素,以尝试将它们作为不同的值读取.

For 2. consider read :: Read a => String -> a. In Haskell we could actually create a list which has the type [forall a. Read a => a], we've essentially deferred the computation and we can now run and rerun elements of the list to attempt to read them as different values.

Typeclasses 也有静态类型,所以有一些检查以确保你不会在没有实例静态调用的情况下卡住",但是 Clojure 是动态类型的,所以我会把这归结为风格上的差异两种语言之间,而不是一种特殊的优势.当然还有一个优点,即类型类的开销比多方法少得多,因为通常可以内联见证记录,并且所有内容都是静态解析的.

Typeclasses also have static types so there's some checking to make sure you're not going to end up "stuck" without an instance to call statically, but Clojure is dynamically typed so I'll chalk this up to a difference in style between the two languages rather than a particular advantage one way or the other. Also of course is the advantage that typeclasses have a lot less overhead than multimethods since generally the witness record can be inlined and everything is resolved statically.

这篇关于Clojure 中的协议和多方法的多态性不如 Haskell 中的类型类强大的原因是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆