I am currently try to get a feeling of the new features in Scala 3/dotty. So I am trying to redo something I tried with shapeless before. Given a heterogenous list of narrowed string types (in shapeless it would be "a" :: "c" :: "f" :: HNil
and in dotty as I understand, the tuples can be utilized ("a", "c", "f")
), I'd like to replace the types according to some mapping. For example consider following pseudocode:
type MyListOfNames = ("a", "c", "f")
type Mapping = ("a" -> "b", "c" -> "d")
// somehow apply the mapping/replacements as the new type alias `MyListOfRenamedNames`
type MyListOfRenamedNames = ("b", "d", "f")
For this, I came up with following code. Remapping a single narrowed String type is working. But I couldn't get it to work with tuples as well:
object A:
trait Remapping
case object ReEmpty extends Remapping
case class ReCons[N1 <: String, N2 <: String, R <: Remapping](n1: N1, n2: N2, rest: R) extends Remapping
type Remapped[X <: String, R <: Remapping] <: String = R match
case ReEmpty.type => X
case ReCons[X, n, _] => n
case ReCons[_, _, rr] => Remapped[X, rr]
type AllRemapped[T <: Tuple, R <: Remapping] <: Tuple = T match
case Unit => Unit
case s *: rest => s match
case String => Remapped[s, R] *: AllRemapped[rest, R]
//this part doesn't compile, giving following compile error:
//type s doesn't satisfy upper bound String
@main def main: Unit =
type RemapAtoBAdCtoD = ReCons["a", "b", ReCons["c", "d", ReEmpty.type]]
val expectedToCompile1: Remapped["a", RemapAtoBAdCtoD] = "b"
val expectedToCompile2: Remapped["c", RemapAtoBAdCtoD] = "d"
val expectedToCompile3: Remapped["f", RemapAtoBAdCtoD] = "f"
val expectedToCompile4: Remapped["a", ReEmpty.type] = "a"
//above examples compile as expected
// val expectedNotToCompile: Remapped["a", RemapAtoBAdCtoD] = "a"
//above example doesn't compile as expected
//I am trying to get following:
type MyList = ("a", "c", "f")
val remapped: AllRemapped[MyList, RemapAtoBAdCtoD] = ("b", "d", "f")
end main
end A
The compilation error I get is Type argument s does not conform to upper bound String
in following line:
s match
case String => Remapped[s, R] *: AllRemapped[rest, R]
I used dotty version 0.18.1-RC1
as it is the latest available one on Scastie. Here is a link that you can experiment on: https://scastie.scala-lang.org/BKzhEV7PRiKyfQ3CE2vjww
Is this not supported, is there a way to achieve this, i.e. how to further restrict the type in type patterns inside a match type (I tried case (s <: String) *: rest =>
, but compiler failed with an error: scala.MatchError: Parens(Ident(s)) (of class dotty.tools.dotc.ast.untpd$Parens)
)? Also is there better way to achieve what I try to do overall (within current capabilities of dotty, like with erased
and inline
)?
Try to introduce helper type and use it as a type pattern
inline
anderased
do not work withtype
.Actually for mapping over a tuple there is standard type
Tuple.Map
although currently in 0.18.1-RC1 I can't make it workWith
inline
you can doTry