8

Haskell では、次の例のようにパラメーター化された型を構築できます。

data Tree a = Leaf | Node a (Tree a) (Tree a)

..その後、型パラメーターがまったく同じ型クラスのインスタンスでもある場合は、それらを型クラスのインスタンスにします (ここでは Eq が例として使用されています。何でもかまいません)。

instance (Eq m) => Eq (Tree m) where
  Leaf == Leaf = True
  Node a b c == Node x y z = (a == x) && (b == y) && (c == z)
  _ == _ = False

同様のことが Scala でどのように可能になるのか疑問に思っています。まず、パラメータ化された型を作成しましょう。

abstract class Tree[T]
case class Leaf[T]() extends Tree [T]
case class Node[T](value: T, left: Tree[T], right: Tree[T]) extends Tree [T]

..実装される型クラスとして、さらに単純な特性を選択します。

trait Serializable {
  def toDifferentString(): String
}

今私ができるようにしたいのはSerializableTreeTSerializable.

部分的にそれを行う方法をいくつか見ることができますが、Haskell のような結果を得る方法はありません。

  • 抽象クラスに型制約:<を追加しますが、一般的ではなくなり、クラスを変更できると想定していますTreeTree
  • Tree[Serializable]からへの暗黙的な変換を作成しますが、Serializableそれが機能するかどうか、そしてそれがどれほど堅牢であるかさえわかりません。

問題にアプローチする良い方法は何ですか?

4

1 に答える 1

12

Scala の型クラス パターンは次のように機能します。

trait Serializable[-T] {
  def toDifferentString(v: T): String
}

class SerializableTree[T : Serializable] extends Serializable[Tree[T]] {
  def toDifferentString(t: Tree[T]) = t match {
    case Leaf() => ""
    case Node(v, left, right) => 
      val vStr = implicitly[Serializable[T]].toDifferentString(v)
      val lStr = toDifferentString(left)
      val rStr = toDifferentString(right)
      s"Node($vStr, $lStr, $rStr)"
  }
}

object SerializableTree {
  implicit def st[T : Serializable]: Serializable[Tree[T]] = new SerializableTree[T]
}

Scalaの型クラスはpatternとして実装されます。型クラスは、これらのメソッドを提供する対象のクラスをパラメーターの 1 つとして受け取る 1 つ以上のメソッドを提供します。

表記T : Serializableコンテキスト バインドであり、 typeの暗黙のパラメーターと同等Serializable[T]です。この暗黙的なパラメーターはによって取得されていますimplicitly[Serializable[T]](メソッドimplicitly[A]は、型の暗黙的なパラメーターを返しますA)。

このオブジェクトSerializableTreeには、ツリーのシリアライザーを生成するために必要な定義が含まれているため、使用するにはインポートする必要があります。多くの場合、型クラスの共通定義は、型クラス自体のオブジェクト コンパニオンに配置されます。これにより、インポートなしで使用できるようになります。

Serializable反変にしたので、 orが必要なSerializable[Tree[T]]ところに a を使えます。Serializable[Node[T]]Serializable[Leaf[T]]

于 2013-09-09T09:56:03.413 に答える