2つのアプローチについての私の考え。
構造タイプ
の構造型を使用できますが、構造型が表示されないためforeach、複数の型で機能するように構造型を作成できます。map例えば:
import collection.generic.CanBuildFrom
object StructuralMap extends App {
type HasMapAndForeach[A] = {
// def map[B, That](f: (A) ⇒ B)(implicit bf: CanBuildFrom[List[A], B, That]): That
def foreach[B](f: (A) ⇒ B): Unit
}
def printValues(xs: HasMapAndForeach[Any]) {
xs.foreach(println _)
}
// def mapValues(xs: HasMapAndForeach[Any]) {
// xs.map(_.toString).foreach(println _)
// }
def forComp1(xs: HasMapAndForeach[Any]) {
for (i <- Seq(1,2,3)) println(i)
}
printValues(List(1,2,3))
printValues(Some(1))
printValues(Seq(1,2,3))
// mapValues(List(1,2,3))
}
scala> StructuralMap.main(new Array[String](0))
1
2
3
4
5
6
7
8
9
10
map上でコメントアウトされたメソッドを参照してください。これは、暗黙的Listに型パラメーターとしてハードコーディングされています。CanBuildFromタイプを一般的に拾う方法があるかもしれません-私はそれをそこにあるScalaタイプの達人への質問として残しておきます。とを置き換えてみHasMapAndForeachましthis.typeたListが、どちらも機能しませんでした。
構造タイプに関する通常のパフォーマンスの警告が適用されます。
Scalaz
構造タイプは行き止まりなので、サポートしたい場合はmap、Travisのscalazアプローチを見て、それがどのように機能するかを見てみましょう。彼の方法は次のとおりです。
def printValues[F[_]: Each](xs: F[Int]) = xs foreach println
def incremented[F[_]: Functor](xs: F[Int]) = xs map (_ + 1)
(以下では、私が間違っている場合は訂正してください。これをscalaz学習体験として使用しています)
型クラスEachとは、の型を、またはに暗黙的に使用できるFunctor型に制限するために使用されます。たとえば、通話中FEach[F]Functor[F]
printValues(List(1,2,3))
コンパイラは、を満たす暗黙的なものを探しますEach[List]。Each特徴は
trait Each[-E[_]] {
def each[A](e: E[A], f: A => Unit): Unit
}
Eachオブジェクトには、暗黙のfor (Each[TraversableOnce]のListサブタイプでTraversableOnceあり、特性は反変です)があります。
object Each {
implicit def TraversableOnceEach[A]: Each[TraversableOnce] = new Each[TraversableOnce] {
def each[A](e: TraversableOnce[A], f: A => Unit) = e foreach f
}
}
「コンテキストバインド」構文に注意してください
def printValues[F[_]: Each](xs: F[Int])
の省略形です
def printValues(xs: F[Int])(implicit ev: Each[F])
これらは両方とも、それが型クラスFのメンバーであることを示していEachます。型クラスを満たす暗黙の値は、evパラメーターとしてprintValuesメソッドに渡されます。
printValuesorメソッドの内部では、typeパラメーターに上限または下限がないためincremented、コンパイラーはorメソッドがあることを認識しませんxs。それがわかる限り、コンテキストバウンドを満たします(型クラスの一部です)。持っているスコープには何がありますか? scalazからの両方とメソッドがあります:mapforeachFFAnyRefforeachmapMAforeachmap
trait MA[M[_], A] {
def foreach(f: A => Unit)(implicit e: Each[M]): Unit = e.each(value, f)
def map[B](f: A => B)(implicit t: Functor[M]): M[B] = t.fmap(value, f)
}
foreachのおよびmapメソッドは、または型クラスMAによって制約されることに注意してください。これらは元のメソッドと同じ制約であるため、制約が満たされ、メソッドを介して暗黙の変換が行われます。EachFunctorMA[F, Int]maImplicit
trait MAsLow extends MABLow {
implicit def maImplicit[M[_], A](a: M[A]): MA[M, A] = new MA[M, A] {
val value = a
}
}
F元のメソッドのタイプはタイプMインになりMAます。
元の呼び出しに渡された暗黙のパラメーターは、暗黙のパラメーターとしてforeachまたはに渡されますmap。の場合、foreachそのeach暗黙のパラメータで呼び出されますe。上記の例では、元のパラメーターがであったため、暗黙のevはタイプでした。同じタイプです。 に委任する呼び出し。_Each[TraversableOnce]ListeforeacheacheforeachTraversableOnce
したがって、呼び出しの順序は次のprintValues(List(1,2,3))とおりです。
new Each[TraversableOnce]-> printValues-> new MA-> MA.foreach-> Each.each->TraversableOnce.foreach
彼らが言うように、余分なレベルの間接参照で解決できない問題はありません:)