gpt4 book ai didi

haskell - Clojure 中的协议(protocol)和多方法在多态性方面不如 Haskell 中的类型类强大的原因是什么?

转载 作者:行者123 更新时间:2023-12-03 10:59:01 26 4
gpt4 key购买 nike

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

现在 Haskell 为 expression problem 提供了一些非常棒的解决方案。与 TypeClass .特别是 - 我们可以这样做:

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

现在 this individual makes the claim :

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 中的协议(protocol)和多方法在多态性方面不如 Haskell 中的类型类强大的原因是什么?

最佳答案

很明显,协议(protocol)只能在第一个且只有第一个参数上分派(dispatch)。这意味着它们大致相当于

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

在哪里 a必须是第一个参数。 Haskell 的类型类让 a出现在函数的任何位置。因此,协议(protocol)的表达能力很容易不如类型类。

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

据我所知,使用多种方法无法完成的一些事情:
  • 返回类型的调度
  • 存储类型类的所有类型的多态值forall a. Foo a => a

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

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

    类型类也具有静态类型,因此需要进行一些检查以确保您不会在没有实例静态调用的情况下最终“卡住”,但 Clojure 是动态类型的,因此我将其归结为两者之间的风格差异一种或另一种语言,而不是一种特定的优势。当然,类型类的开销也比多方法少得多,因为通常可以内联见证记录并且静态解决所有问题。

    关于haskell - Clojure 中的协议(protocol)和多方法在多态性方面不如 Haskell 中的类型类强大的原因是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22040115/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com