Haskell 的类型类和 Go 的接口
Posted
技术标签:
【中文标题】Haskell 的类型类和 Go 的接口【英文标题】:Haskell's TypeClasses and Go's Interfaces 【发布时间】:2011-02-28 05:57:49 【问题描述】:Haskell 的 TypeClasses 和 Go 的 Interfaces 有什么异同?两种方法的相对优缺点是什么?
【问题讨论】:
采用单一方法interface
的 API 可以重写为采用函数类型。见***.com/a/63557675/12817546。
【参考方案1】:
看起来 only in superficial ways 是 Go 接口,类似于 Haskell 中的单参数类型类(构造函数类)。
方法与接口类型相关联 对象(特定类型)可能具有该接口的实现我不清楚 Go 是否以任何方式通过接口支持有界多态性,这是类型类的主要目的。也就是说,在Haskell中,接口方法可以用在不同的类型上,
class I a where
put :: a -> IO ()
get :: IO a
instance I Int where
...
instance I Double where
....
所以我的问题是 Go 是否支持类型多态。如果不是,它们根本不像类型类。而且它们没有可比性。
Haskell 的类型类允许通过“泛型”——更高种类的多态——强大的代码重用——cross-language support for such forms of generic program is this paper 的一个很好的参考。
通过类型类的特殊或有界多态是well described here。这是 Haskell 中类型类的主要目的,并且没有通过 Go 接口解决,这意味着它们根本不是非常相似。接口严格来说没有那么强大 - 一种零阶类型类。
【讨论】:
确实,两者之间的唯一关系似乎是在这两种情况下,“方法”都独立于“类”而存在。就是这样。 Go 的接口支持“有界多态性”,正如 Wikipedia 文章中严格定义的那样,只需在函数签名中命名您想要的接口即可。例如,如果我写“func foo(a, b IBar)”,那么编译器会确保我只能传入支持 IBar 的结构。然而,Haskell 的类型类支持非结构类型,甚至复合绑定(例如,func foo(a, b (IBar && IBaz))在 Go 中也是非法的,但是 (IBar a, IBaz a) => foo :: a -> b -> ... 完全合法)。您必须在 Go 中创建一个复合接口才能执行类似的操作(访问 io.ReadCloser)。【参考方案2】:我将补充 Don Stewart 的出色回答,即 Haskell 类型类的一个令人惊讶的结果是您可以在编译时使用逻辑编程来生成任意多个类的实例。 (Haskell 的 type-class 系统实际上包括 Prolog 的一个无剪切子集,与 Datalog 非常相似。)该系统在 QuickCheck 库中得到了很好的利用。或者对于一个非常简单的示例,您可以查看如何定义version of Boolean complement (not
) that works on predicates of arbitrary arity。我怀疑这种能力是类型类系统的意外结果,但事实证明它非常强大。
Go 没有类似的东西。
【讨论】:
【参考方案3】:-
在 haskell 中,类型类实例化是显式的(即,您必须说
instance Foo Bar
才能让 Bar 成为 Foo 的实例),而在 go 中实现接口是隐式的(即,当您定义一个定义正确方法的类时,它自动实现相应的接口,而不必说像implement InterfaceName
)。
接口只能描述接口实例是接收者的方法。在类型类中,实例化类型可以出现在任何参数位置或函数的返回类型(即,您可以说,如果 Foo 是 Bar 类型的实例,则必须有一个名为 baz 的函数,它接受一个 Int 并返回一个 Foo -你不能用接口这么说)。
【讨论】:
缺乏多态性严重限制了 Go 接口与类型类相关的程度。我想说的是,如果实例方法中没有多态性,它们并没有真正相关,除了表面上。 人们在询问它表明他们显然是相关的。我会说 Go 接口是 Haskell 类型类提供的一个严格的子集。例如,你可以在 Go 中做的所有事情在 Haskell 中都是可能的(微不足道,甚至),但反过来则不然。 我不确定您希望如何将“Bar”类型设为要求。通常你有一个“类型类的实例”,它要求类型实例是特定类型。但是类型类本身仅包含未绑定到特定类型的占位符(“未来”类型类实例)。 Go 的接口不同之处在于它们隐式绑定到类型,而 Haskell 类型类必须实例化/显式实现。【参考方案4】:非常表面的相似之处,Go 的接口更像是 OCaml 中的结构子类型。
【讨论】:
【参考方案5】:C++ Concepts(没有进入 C++0x)就像 Haskell 类型的类。还有一些在 Haskell 中根本不存在的“公理”。它们让您将诸如 monad 法则之类的东西正式化。
【讨论】:
以上是关于Haskell 的类型类和 Go 的接口的主要内容,如果未能解决你的问题,请参考以下文章