Reputation: 1007
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.
Is there a way to impose this restriction in Scala?
Upvotes: 0
Views: 101
Reputation: 44957
EDIT
Assuming XY-problem. Now this posting has two answers:
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
.
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.
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.
Define your type-class first, for example with the constraint that one sholud be able to iterate through 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:
class MyClass[X, F[_] : MyTC] {
val states: X
val transform: X => F[X]
}
Then simply define instances of MyTC
for List
, Set
, or Id
:
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
:
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]
.
Upvotes: 1
Reputation: 51683
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
Upvotes: 2