Scala コレクションのいくつかの拡張メソッドを作成しようとしていますが、それらを完全に生成するのに問題が発生しています。
tailOption の最初の試行では、次のような結果が得られます。
implicit class TailOption[A, Repr <: GenTraversableLike[A, Repr]](val repr: Repr) {
def tailOption: Option[Repr] =
if (repr.isEmpty) None
else Some(repr.tail)
}
残念ながら、これは機能しません:
scala> List(1,2,3).tailOption
<console>:19: error: value tailOption is not a member of List[Int]
List(1,2,3).tailOption
Scala 2.10 は IsTraversableLike 型クラスを提供して、この種のものをすべてのコレクション (文字列などの奇妙なものを含む) に適応させるのに役立ちます。
これにより、たとえば、tailOption を非常に簡単に実装できます。
implicit class TailOption[Repr](val r: Repr)(implicit fr: IsTraversableLike[Repr]) {
def tailOption: Option[Repr] = {
val repr = fr.conversion(r)
if (repr.isEmpty) None
else Some(repr.tail)
}
}
scala> List(1,2,3).tailOption
res12: Option[List[Int]] = Some(List(2, 3))
scala> "one".tailOption
res13: Option[String] = Some(ne)
結果は正しいタイプです: Option[<input-type>]
. 具体的には、 「 Repr
tail Repr
.
残念ながら、このトリックを使用してコレクションの要素の型を保持することはできないようです。要素を返すメソッドを呼び出すことができません。
IsTraversableLike
にはメンバー A がありますが、あまり役に立ちません。特に、元の要素の型を再構築できず、メンバーの型が同等ではありません。たとえば、さらに作業を行わないと、headTailOption
次のようになります。
implicit class HeadTailOption[Repr](val r: Repr)(implicit val fr: IsTraversableLike[Repr]) {
def headTailOption: Option[(fr.A, Repr)] = {
val repr = fr.conversion(r)
if (repr.isEmpty) None
else Some(repr.head -> repr.tail)
}
}
scala> val Some((c, _)) = "one".headTailOption
c: _1.fr.A forSome { val _1: HeadTailOption[String] } = o
ご覧のとおり、c は見事なバロック型を持っています。ただし、この型はChar と同等ではありません。
scala> val fr = implicitly[IsTraversableLike[String]]
fr: scala.collection.generic.IsTraversableLike[String] = scala.collection.generic.IsTraversableLike$$anon$1@60ab6a84
scala> implicitly[fr.A <:< Char]
<console>:25: error: Cannot prove that fr.A <:< Char.
implicitly[fr.A <:< Char]
私は、どれも役に立たないことを含め、あらゆる種類のトリックを試しRepr[A] <: GenTraversableLike[A, Repr[A]]
ました。誰でもheadTailOption
適切な型を返すための魔法のソースを考え出すことができますか?
val headTailString: Option[(Char, String)] = "one".headTailOption
val headTailList: Option[(Int, List[Int])] = List(1,2,3).headTailOption