Rust中的traits和Haskell中的类型类有什么区别?

Log*_*ins 143 haskell traits rust

性状拉斯特似乎至少在表面上相似的类型类在Haskell,但我见过的人写的,有他们之间的一些差异.我想知道这些差异究竟是什么.

AJF*_*mar 57

在基础层面上,没有太大区别,但它们仍然存在.

Haskell将类型类中定义的函数或值描述为"方法",就像traits在它们所包含的对象中描述OOP方法一样.但是,Haskell以不同的方式处理这些问题,将它们视为单独的值而不是将它们固定到对象上,因为OOP会引导人们去做.这是关于最明显的表面水平差异.

直到最近,Rust无法做到的一件事是高阶类型特征,例如臭名昭​​着FunctorMonad类型类.

这意味着Rust特征只能描述通常所谓的"具体类型",换句话说,没有通用参数.但是,Haskell可以生成高阶类型类,它使用类似于高阶函数如何使用其他函数的类型,使用一个来描述另一个函数.我们无法实现Rust中提到的类型类,因为它不支持在Haskell中被认为是基本的,甚至是必需的这个特性.值得庆幸的是,最近已经实现了相关项目.*但是,这不是惯用的Rust,通常被认为是'hack'.

如评论中所述,GHC(Haskell的主要编译器)支持类型类的更多选项,包括多参数(即涉及的多种类型)类型类和函数依赖项,这是一个允许类型级计算的可爱选项,这也是值得一提的. ,并引导打字家庭.据我所知,Rust既没有funDeps也没有打字系列,虽然它可能在未来.†

总而言之,虽然表面上的特征和类型似乎相当,但在考虑众多品质时,它们在进行更深入比较时确实存在很多差异.


*另一方面,Swift尽管有特质,却没有这种更高级别的机制.可能是未来的语言更新?

†在Haskell的类型类一个不错的文章(包括类型化更高的),可以发现在这里,和锈的特点同样好的一个保持这里,虽然是不幸的是一点点外的日期.

  • Rust 仍然没有任何形式的更高级的类型。“臭名昭著”需要理由。函子作为一个概念非常普遍和有用。类型族与关联类型相同。函数依赖本质上与关联类型(包括在 Haskell 中)是多余的。Rust 缺少的东西。Fundeps 是注入注解。反过来说,Rust 的特性和 Haskell 的类型类在表面上是不同的,但是当你往下看时,许多差异就消失了。仍然存在的差异主要是语言运行的不同领域所固有的。 (4认同)

Lii*_*Lii 14

我认为当前的答案忽略了Rust traits和Haskell类型类之间最根本的区别.这些差异与特征与面向对象的语言结构相关的方式有关.有关此信息,请参阅Rust书籍.

  1. 特征声明会创建特征类型.这意味着您可以声明这种类型的变量(或者更确切地说,类型的引用).您还可以使用特征类型作为函数,结构字段和类型参数实例化的参数.

    特征引用变量可以在运行时包含不同类型的对象,只要引用对象的运行时类型实现特征即可.

    // The shape variable might contain a Square or a Circle, 
    // we don't know until runtime
    let shape: &Shape = get_unknown_shape();
    
    // Might contain different kinds of shapes at the same time
    let shapes: Vec<&Shape> = get_shapes();
    
    Run Code Online (Sandbox Code Playgroud)

    这不是类型类的工作方式.类型类不创建任何类型,因此您无法使用类名声明变量.类型类充当类型参数的边界,但类型参数必须使用具体类型实例化,而不是类型类本身.

    您不能拥有实现相同类型类的不同类型的不同事物的列表.(相反,在Haskell中使用存在类型来表达类似的东西.)注1

  2. 可以动态调度特征方法.这与上面的子弹中描述的内容密切相关.

    动态分派意味着参考点的对象的运行时类型用于确定通过引用调用的方法.

    let shape: &Shape = get_unknown_shape();
    
    // This calls a method, which might be Square.area or
    // Circle.area depending on the runtime type of shape
    print!("Area: {}", shape.area());
    
    Run Code Online (Sandbox Code Playgroud)

    同样,在Haskell中使用存在类型.

结论

在我看来,特征与类型类基本上是相同的概念.此外,它们还具有面向对象接口的功能.

(Haskell的类型类更高级,因为Haskell具有例如更高级的类型和扩展,如多参数类型类.但我认为它们基本相同.)


注1:Rust的最新版本具有和更新,以区分特征名称作为类型的使用和特征名称作为边界的使用.我是一个特征类型,名称以dyn关键字为前缀.有关详细信息,请参阅此答案.

  • “类型类不创建类型”——我认为最好将 `dyn Trait` 理解为存在类型的一种形式,因为它们与特征/类型类相关。我们可以将 `dyn` 视为边界上的运算符,将它们投影到类型,即 `dyn : List Bound -&gt; Type`。把这个想法带到 Haskell,关于“所以你不能用类名声明变量”,我们可以在 Haskell 中间接做到这一点:`data Dyn (c :: * -&gt; Constraint) = forall (t : : 类型)。ct =&gt; D t`。定义了这个之后,我们可以使用 `[D True, D "abc", D 42] :: [D Show]`。 (3认同)

小智 8

Rust的"特征"类似于Haskell的类型类.

与Haskell的主要区别在于traits只干涉带点符号的表达式,即a.foo(b)形式.

Haskell类型类扩展到更高阶类型.Rust特征只支持更高阶类型,因为它们在整个语言中都缺失,即它不是特征和类型类之间的哲学差异

  • Rust 中的特征不“只干预带有点符号的表达式”。例如,考虑没有方法,只有非方法关联函数的“默认”特征。 (3认同)