[英]How to define a type parameter that can be either a type or a container for that type?
I want to define a class like this: 我想定义一个这样的类:
class MyClass[C,X](
val states: C,
val transform: C => X
)
But X
can only be equals to C
or a container for C
, like List[C]
or Set[C]
-- it does not make sense for the problem at hand if X
is defines as anything else. 但
X
只能是等于C
或容器C
,像List[C]
或Set[C]
-它不手头意义的问题,如果X
是定义为别的。
Is there a way to impose this restriction in Scala? 有没有办法在Scala中强加此限制?
You can try 你可以试试
import scala.language.higherKinds
class MyClass[C, F[_]](
val states: C,
val transform: C => F[C]
)
type Id[A] = A
new MyClass[Int, Set](1, Set(_)) // Set[Int] is a container for Int
new MyClass[String, List]("a", List(_)) // List[String] is a container for String
new MyClass[Boolean, Id](true, x => x) // Id[Boolean] is Boolean itself
EDIT 编辑
Assuming XY-problem. 假设XY问题。 Now this posting has two answers:
现在,此帖子有两个答案:
X
X
Subclassing-solution 子分类解决方案
If you run 如果你跑
List(List(0), Set(0))
in the interpreter, you will see that List
and Set
unify only at Iterable
. 在解释器中,您将看到
List
和Set
仅在Iterable
处统一。
Thus, the most specific restriction you can make is: 因此,您可以做出的最具体的限制是:
import scala.language.higherKinds
class MyClass[C, Container[X] <: collection.immutable.Iterable[X]] (
val states: C,
val transform: C => Container[C]
)
I wouldn't advise to make it this generic though. 我不建议使它如此通用。 If in doubt, take
List
first, generalize later only if it's actually necessary. 如有疑问,请首先使用
List
,然后仅在确实有必要时才进行概括。
Typeclass-solution 类型类解决方案
From your comment, it looks as if it's an XY-problem, and what you actually want is a type constructor F
with an appropriate type-class. 从您的评论看来,这似乎是一个XY问题,而您真正想要的是带有适当类型类的类型构造函数
F
Define your type-class first, for example with the constraint that one sholud be able to iterate through F
: 首先定义您的类型类,例如,限制一个类能够遍历
F
:
trait MyTC[F[_]] {
def hasIterator[X](fx: F[X]): Iterator[X]
}
Then define MyClass
for arbitrary F
for which there is an instance of the typeclass: 然后为存在类型类实例的任意
F
定义MyClass
:
class MyClass[X, F[_] : MyTC] {
val states: X
val transform: X => F[X]
}
Then simply define instances of MyTC
for List
, Set
, or Id
: 然后只需为
List
, Set
或Id
定义MyTC
实例:
implicit object ListMyTC extends MyTC[List] {
def hasIterator[X](lx: List[X]): Iterator[X] = lx.iterator
}
type Id[X] = X
implicit object ListMyTC extends MyTC[Id] {
def hasIterator[X](x: X): Iterator[X] = Iterator(x)
}
And then you can use MyClass
with List
s or with Id
: 然后可以将
MyClass
与List
或Id
:
val m1 = new MyClass[Int, List] { ... } // Integer states, transforms to List
val m2 = new MyClass[String, Id] { ... } // String-labeled states, transforms to other `String`
etc. 等等
The idea is essentially to replace your attempt to extensionally enumerate all the container types for which you think your construction might work by an intensional definition, that accepts any F
that can prove that it satisfies all the requirements in MyTC
by providing an instance of MyTC[F]
. 这个想法基本上是更换您尝试外延上列举了,你认为你的建筑可能是由描述法工作的所有容器类型,即接受任何
F
能够证明其满足所有要求MyTC
提供的实例MyTC[F]
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.