당신은 모든 Traversables에 대해이 작업을 수행 할 수 그들이 돈으로 지도가 Traversable보다 더 구체적인 것을 반환한다고 보장하지 않습니다.
아래의 업데이트 2를 참조하십시오.
import collection.generic.CanBuildFrom
import collection.TraversableLike
class TraversableW[CC[X] <: TraversableLike[X, CC[X]], A](value: CC[A]) {
def mapmap(f: A => A)(implicit cbf: CanBuildFrom[CC[A], A, CC[A]]): CC[A]
= value.map(f andThen f)
def mapToString(implicit cbf: CanBuildFrom[CC[A], String, CC[String]]): CC[String]
= value.map(_.toString)
}
object TraversableW {
implicit def TraversableWTo[CC[X] <: TraversableLike[X, CC[X]], A](t: CC[A]): TraversableW[CC, A]
= new TraversableW[CC, A](t)
}
locally {
import TraversableW._
List(1).mapmap(1+)
List(1).mapToString
// The static type of Seq is preserved, *and* the dynamic type of List is also
// preserved.
assert((List(1): Seq[Int]).mapmap(1+) == List(3))
}
UPDATE 나는 TraversableW
두 가지 유형 매개 변수보다는 알렉세이의 솔루션으로 하나 개의 매개 변수를 받아들이는 이유를 설명하기 위해 또 다른 포주 방법, mapToString
을 추가했습니다. CC
매개 변수는 더 높은 종류의 유형이며 원본 컬렉션의 컨테이너 유형을 나타냅니다. 두 번째 매개 변수 A
은 원본 컬렉션의 요소 유형을 나타냅니다. 따라서 mapToString
메소드는 CC[String
이라는 다른 요소 유형의 원래 컨테이너 유형을 반환 할 수 있습니다.
업데이트 2 @oxbow_lakes 주석 덕분에, 저는 이것을 다시 생각했습니다. 참으로 직접 포주로 CC[X] <: Traversable[X]
, TraversableLike
이 꼭 필요한 것은 아닙니다. 주석 인라인 :
import collection.generic.CanBuildFrom
import collection.TraversableLike
class TraversableW[CC[X] <: Traversable[X], A](value: CC[A]) {
/**
* A CanBuildFromInstance based purely the target element type `Elem`
* and the target container type `CC`. This can be converted to a
* `CanBuildFrom[Source, Elem, CC[Elem]` for any type `Source` by
* `collection.breakOut`.
*/
type CanBuildTo[Elem, CC[X]] = CanBuildFrom[Nothing, Elem, CC[Elem]]
/**
* `value` is _only_ known to be a `Traversable[A]`. This in turn
* turn extends `TraversableLike[A, Traversable[A]]`. The signature
* of `TraversableLike#map` requires an implicit `CanBuildFrom[Traversable[A], B, That]`,
* specifically in the call below `CanBuildFrom[Traversable[A], A CC[A]`.
*
* Essentially, the specific type of the source collection is not known in the signature
* of `map`.
*
* This cannot be directly found instead we look up a `CanBuildTo[A, CC[A]]` and
* convert it with `collection.breakOut`
*
* In the first example that referenced `TraversableLike[A, CC[A]]`, `map` required a
* `CanBuildFrom[CC[A], A, CC[A]]` which could be found.
*/
def mapmap(f: A => A)(implicit cbf: CanBuildTo[A, CC]): CC[A]
= value.map[A, CC[A]](f andThen f)(collection.breakOut)
def mapToString(implicit cbf: CanBuildTo[String, CC]): CC[String]
= value.map[String, CC[String]](_.toString)(collection.breakOut)
}
object TraversableW {
implicit def TraversableWTo[CC[X] <: Traversable[X], A](t: CC[A]): TraversableW[CC, A]
= new TraversableW[CC, A](t)
}
locally {
import TraversableW._
assert((List(1)).mapmap(1+) == List(3))
// The static type of `Seq` has been preserved, but the dynamic type of `List` was lost.
// This is a penalty for using `collection.breakOut`.
assert((List(1): Seq[Int]).mapmap(1+) == Seq(3))
}
다른 점은 무엇입니까?우리는 단지 Traversable[A]
에서 특정 컬렉션 하위 유형을 복구 할 수 없기 때문에 collection.breakOut
을 사용해야했습니다.
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
val b = bf(repr)
b.sizeHint(this)
for (x <- this) b += f(x)
b.result
}
는 Builder
b
는 map
통해 동적 유형을 유지하는기구이며 원래 수집하여 초기화된다. 그러나 CanBuildFrom
은 에 대한 모든 지식을 부인했습니다. 형식 인수 Nothing
을 통해에서입니다. 당신이 def foo(a: Nothing) = 0
를 호출 할 수있는 것보다
def breakOut[From, T, To](implicit b : CanBuildFrom[Nothing, T, To]) =
new CanBuildFrom[From, T, To] {
def apply(from: From) = b.apply();
def apply() = b.apply()
}
우리는 더 이상 b.apply(from)
를 호출 할 수 없습니다 : 당신이 Nothing
로 할 수있는 모든 breakOut
이 바로 이러한 작업을 수행하는 것 인, 그것을 무시한다.
완벽하게 작동합니다! –
Scalaz에서 약간 다른 접근 방식을 취했습니다. 좀 더 강력합니다. http://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/CanBuildAnySelf.scala#L24 http : //github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/Functor.scala#L28 – retronym
필자는 코드를 편집 할 수있는 권리가 없지만 코드 형식은 아마도 블록을 확장하여 예제에 가져 오기를 포함해야합니까? 건배! – pr1001