在 Scala 中使用协变不可变集合
Working with covariant immutable collections in Scala
我正在尝试创建一个适用于具有 take
、slice
和 drop
的任何集合的函数。也就是说,我想创建一个适用于 IndexedSeq[Boolean]
和 Vector[Boolean]
的函数,返回相同类型的对象。这是我在看过这个
之后尝试过的
and trying to use IndexedSeqLike
instead of Ordering
, to no avail
trait MutateLike[+T,-Y] {
def apply[U >: T, Y](eo: U): Y
}
case object Mutate extends MutateLike[IndexedSeq[Boolean],IndexedSeq[Boolean]]{
def apply[U >: IndexedSeq[Boolean],IndexedSeq[Boolean]]( eo : U ): IndexedSeq[Boolean] = {
val point = (eo.length * scala.util.Random.nextDouble).toInt
eo.take( point - 1 ) ++ eo.slice( point-1,point ).map(!_) ++ eo.drop( point )
}
}
在尝试了许多其他事情之后。但是,它不起作用并产生 value length is not a member of type parameter U
的错误。但是 U 与 T 是协变的,在本例中是 IndexedSeq,对吗?
任何帮助将不胜感激。
我认为你让你的生活变得比它需要的复杂得多。试试这个
case object Mutate{
def apply( eo : IndexedSeq[Boolean] ): IndexedSeq[Boolean] = {
val point = (eo.length * scala.util.Random.nextDouble).toInt
eo.take( point - 1 ) ++ eo.slice( point-1,point ).map(!_) ++ eo.drop( point )
}
}
scala> Mutate( IndexedSeq( true, false, false, true, false, false ) )
res8: IndexedSeq[Boolean] = Vector(false, false, false, true, false, false)
scala> Mutate( Vector( true, false, false, true, false, false ) )
res9: IndexedSeq[Boolean] = Vector(false, false, false, true, false, false)
这就是直接的、老式的面向对象多态性。 A Vector[Boolean]
是 A IndexedSeq[Boolean]
,因此它可以替代它。
通过声明 MutateLike
及其变体,您正在决定 MutateLike
的哪种参数化被视为继承自 MutateLike
的其他参数。但这不是你有兴趣表达或尝试做的。
(当然根本不需要使用对象声明。您可以将 mutate
定义为一个简单的函数。)
也许你想要这样的东西:
import scala.util.Random
import scala.collection.generic.CanBuildFrom
import scala.collection.SeqLike
def mutate[Repr, To](xs: SeqLike[Boolean, Repr], rng: Random)(implicit ev: CanBuildFrom[Repr, Boolean, To]) = {
val builder = ev.apply()
val iter = xs.iterator
var i = rng.nextInt(xs.length)
while (i > 0) { i -= 1; builder += iter.next }
builder += !iter.next
while (iter.hasNext) builder += iter.next
builder.result
}
现在
val xs = Array(true, true, false, true, false)
mutate(xs, new scala.util.Random(111L))
结果
Array[Boolean] = Array(true, true, false, false, false)
和
val xs = Vector(true, true, false, true, false)
mutate(xs, new scala.util.Random(111L))
结果
scala.collection.immutable.Vector[Boolean] = Vector(true, true, false, false, false)
mutate
方法也可以很容易地概括为处理 Booleans
以外类型的集合,如下所示:
def mutate[Repr, To, A](xs: SeqLike[A, Repr], f: A => A, rng: Random)(implicit ev: CanBuildFrom[Repr, A, To]) = {
val builder = ev.apply()
val iter = xs.iterator
var i = rng.nextInt(xs.length)
while (i > 0) { i -= 1; builder += iter.next }
builder += f(iter.next)
while (iter.hasNext) builder += iter.next
builder.result
}
然后
Seq.iterate("I am what I am", 16){ s=>
mutate(s, (ch: Char) => (ch ^ 3).toChar, rng)
}.mkString("\n")
结果
I am what I am
J am what I am
I am what I am
J am what I am
J#am what I am
J#am what I bm
J#am what I#bm
J#am what#I#bm
J#am what#I bm
J#am whaw#I bm
J am whaw#I bm
J am what#I bm
J am what#I#bm
J am what#J#bm
I am what#J#bm
J am what#J#bm
我正在尝试创建一个适用于具有 take
、slice
和 drop
的任何集合的函数。也就是说,我想创建一个适用于 IndexedSeq[Boolean]
和 Vector[Boolean]
的函数,返回相同类型的对象。这是我在看过这个
and trying to use
IndexedSeqLike
instead ofOrdering
, to no avail
trait MutateLike[+T,-Y] {
def apply[U >: T, Y](eo: U): Y
}
case object Mutate extends MutateLike[IndexedSeq[Boolean],IndexedSeq[Boolean]]{
def apply[U >: IndexedSeq[Boolean],IndexedSeq[Boolean]]( eo : U ): IndexedSeq[Boolean] = {
val point = (eo.length * scala.util.Random.nextDouble).toInt
eo.take( point - 1 ) ++ eo.slice( point-1,point ).map(!_) ++ eo.drop( point )
}
}
在尝试了许多其他事情之后。但是,它不起作用并产生 value length is not a member of type parameter U
的错误。但是 U 与 T 是协变的,在本例中是 IndexedSeq,对吗?
任何帮助将不胜感激。
我认为你让你的生活变得比它需要的复杂得多。试试这个
case object Mutate{
def apply( eo : IndexedSeq[Boolean] ): IndexedSeq[Boolean] = {
val point = (eo.length * scala.util.Random.nextDouble).toInt
eo.take( point - 1 ) ++ eo.slice( point-1,point ).map(!_) ++ eo.drop( point )
}
}
scala> Mutate( IndexedSeq( true, false, false, true, false, false ) )
res8: IndexedSeq[Boolean] = Vector(false, false, false, true, false, false)
scala> Mutate( Vector( true, false, false, true, false, false ) )
res9: IndexedSeq[Boolean] = Vector(false, false, false, true, false, false)
这就是直接的、老式的面向对象多态性。 A Vector[Boolean]
是 A IndexedSeq[Boolean]
,因此它可以替代它。
通过声明 MutateLike
及其变体,您正在决定 MutateLike
的哪种参数化被视为继承自 MutateLike
的其他参数。但这不是你有兴趣表达或尝试做的。
(当然根本不需要使用对象声明。您可以将 mutate
定义为一个简单的函数。)
也许你想要这样的东西:
import scala.util.Random
import scala.collection.generic.CanBuildFrom
import scala.collection.SeqLike
def mutate[Repr, To](xs: SeqLike[Boolean, Repr], rng: Random)(implicit ev: CanBuildFrom[Repr, Boolean, To]) = {
val builder = ev.apply()
val iter = xs.iterator
var i = rng.nextInt(xs.length)
while (i > 0) { i -= 1; builder += iter.next }
builder += !iter.next
while (iter.hasNext) builder += iter.next
builder.result
}
现在
val xs = Array(true, true, false, true, false)
mutate(xs, new scala.util.Random(111L))
结果
Array[Boolean] = Array(true, true, false, false, false)
和
val xs = Vector(true, true, false, true, false)
mutate(xs, new scala.util.Random(111L))
结果
scala.collection.immutable.Vector[Boolean] = Vector(true, true, false, false, false)
mutate
方法也可以很容易地概括为处理 Booleans
以外类型的集合,如下所示:
def mutate[Repr, To, A](xs: SeqLike[A, Repr], f: A => A, rng: Random)(implicit ev: CanBuildFrom[Repr, A, To]) = {
val builder = ev.apply()
val iter = xs.iterator
var i = rng.nextInt(xs.length)
while (i > 0) { i -= 1; builder += iter.next }
builder += f(iter.next)
while (iter.hasNext) builder += iter.next
builder.result
}
然后
Seq.iterate("I am what I am", 16){ s=>
mutate(s, (ch: Char) => (ch ^ 3).toChar, rng)
}.mkString("\n")
结果
I am what I am
J am what I am
I am what I am
J am what I am
J#am what I am
J#am what I bm
J#am what I#bm
J#am what#I#bm
J#am what#I bm
J#am whaw#I bm
J am whaw#I bm
J am what#I bm
J am what#I#bm
J am what#J#bm
I am what#J#bm
J am what#J#bm