web-dev-qa-db-ja.com

RustとHaskellのtypeclassesの特性の違いは何ですか?

Traits in Rustは少なくとも表面的には typeclasses Haskellに似ているように見えるが、人々はそれらの間にいくつかの違いがあると書いているのを見た。私はこれらの違いが何であるかを正確に疑問に思っていました。

139
LogicChains

基本的なレベルでは、大きな違いはありませんが、それらはまだあります。

Haskellは、特性がOOPメソッドを囲むオブジェクトのメソッドを記述するように、タイプクラスで定義された関数または値を 'メソッド'として記述します。しかし、Haskellはこれらを別々に扱い、それらを個別の値として扱うのではなくOOPのようにオブジェクトに固定することで、1つを実行できます。これは、表面レベルの最も明らかな違いです。

Rustは最近までできなかったことの1つは、高次型特性でした。悪名高いFunctorおよびMonad型クラス。

つまり、Rust traitsは、しばしば「具体的なタイプ」と呼ばれるもの、つまり総称的な引数のないものだけを記述できます。しかし、Haskellは、同様のタイプを使用する高次タイプクラス高次関数が他の関数を使用して、別の関数を記述する方法については、Haskellでは基本的であり、さらには必須と見なされるこの機能をサポートしていなかったため、Rustで前述した型クラスを実装できませんでした。これは最近 関連アイテム 。*で実装されましたが、これは慣用的なRustではなく、一般に「ハック」と見なされます。

コメントで述べたように、GHC(Haskellの主要なコンパイラー)は multi-parameter (つまり、多くの型が関係している)型クラス、および 機能依存性 、型レベルの計算を可能にし、 型族 につながる素敵なオプションです。私の知る限り、RustにはfunDepsもタイプファミリーもありませんが、将来的にはそうなる可能性があります。†

全体として、表面上では特性と型クラスは同等に見えるかもしれませんが、多くの品質を考慮すると、それらをより深く比較すると多くの違いがあります。


*サイドノートでは、Swiftには特性がありますが、そのような高型付​​けのメカニズムはありません。言語の将来の更新でしょうか?

†Haskellの型クラス(より高い型の型クラスを含む)に関する素敵な記事を見つけることができます here 、そしてRustの特性に関する同等の良いものは here を保持していますが、残念ながら少しです時代遅れ。

56
AJFarmar

現在の答えは、Rust traitsとHaskell型クラスの最も基本的な違いを見落としていると思います。これらの違いは、特徴がオブジェクト指向言語構成に関連する方法に関係しています。 Rust book

  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();
    

    これは、型クラスの仕組みではありません。 型クラスは型を作成しないため、クラス名で変数を宣言することはできません。 型クラスは型パラメーターの境界として機能しますが、型パラメーターは型クラス自体ではなく、具象型でインスタンス化する必要があります。

    同じ型クラスを実装する異なる型の異なるもののリストを持つことはできません。 (代わりに、Haskellでは同様のことを表現するために実存型が使用されます。) 注1

  2. Traitメソッドは動的にディスパッチできます。これは、上記のセクションで説明されていることに強く関連しています。

    動的ディスパッチとは、参照が指すオブジェクトの実行時タイプを使用して、参照を通じて呼び出されるメソッドを決定することを意味します。

    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());
    

    繰り返しになりますが、このためにHaskellでは存在型が使用されます。

結論として

特性は本質的に型クラスと同じ概念であるように思えます。さらに、これらはオブジェクト指向インターフェースの機能を備えています。

一方、Haskellの型クラスは、より高度な型とマルチパラメーター型クラスなどの拡張機能を備えているため、Haskellの型クラスはより高度です。しかし、それらは本質的に同じだと思います。


注1:Rustの最近のバージョンには、タイプとしての特性名の使用と境界としての特性名の使用を区別するための更新があります。特性タイプでは、名前の前にdynキーワードが付きます。たとえば、詳細については、この answer を参照してください。

13
Lii

Rustの「特性」は、Haskellの型クラスに類似しています。

Haskellとの主な違いは、特性がドット表記の式、つまりa.foo(b)の形式に対してのみ介入することです。

Haskell型クラスは、高次型に拡張されます。 Rust特性は、言語全体から欠落しているため、高次型のみをサポートしません。つまり、特性と型クラスの哲学的な違いではありません。

8
Anuj Gupta