如何用 dotty 中的元组大小写的缩小字符串类型头部编写匹配类型模式?
How do I write a match type pattern with a narrowed String type head of tuple case in dotty?
我目前正在尝试感受一下 Scala 3/dotty 中的新特性。所以我想重做一些我以前用无形尝试过的东西。给定一个缩小的字符串类型的异构列表(在 shapeless 中它将是 "a" :: "c" :: "f" :: HNil
并且据我所知,在 dotty 中,可以使用元组 ("a", "c", "f")
),我想根据一些映射替换类型.例如考虑以下伪代码:
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")
为此,我想出了以下代码。重新映射单个缩小的 String 类型正在工作。但我也无法让它与元组一起工作:
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
我得到的编译错误是 Type argument s does not conform to upper bound String
在以下行中:
s match
case String => Remapped[s, R] *: AllRemapped[rest, R]
我使用了 dotty 版本 0.18.1-RC1
,因为它是 Scastie 上最新可用的版本。这是您可以试验的 link:https://scastie.scala-lang.org/BKzhEV7PRiKyfQ3CE2vjww
这是不支持的吗,有没有办法实现这个,即如何进一步限制匹配类型内的类型模式中的类型(我试过case (s <: String) *: rest =>
,但编译器失败并出现错误:scala.MatchError: Parens(Ident(s)) (of class dotty.tools.dotc.ast.untpd$Parens)
)?是否还有更好的方法来实现我总体上尝试做的事情(在 dotty 的当前能力范围内,例如 erased
和 inline
)?
尝试引入辅助类型并将其用作类型模式
type Hlp[X <: String, Rest <: Tuple] = X *: Rest
type AllRemapped[T <: Tuple, R <: Remapping] <: Tuple = T match {
case Unit => Unit
case Hlp[s, rest] => Remapped[s, R] *: AllRemapped[rest, R]
}
inline
和 erased
不适用于 type
。
实际上对于元组的映射有标准类型Tuple.Map
虽然目前在 0.18.1-RC1 中我不能让它工作
type AllRemapped[T <: Tuple, R <: Remapping] = Tuple.Map[T, [X <: String] =>> Remapped[X, R]]
//Type argument [X <: String] => A.Remapped[X, R] does not conform to upper bound [_] => Any
用inline
你可以做到
inline def g(x: "a" | "c" | "f") <: String = inline x match {
case "a" => "b"
case "c" => "d"
case "f" => "f"
}
g("a"): "b"
g("c"): "d"
g("f"): "f"
// g("x") // doesn't compile
尝试
sealed 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]
}
inline def getRemapped[X <: String & Singleton, R <: Remapping] erased (x: X, r: R) <: String = inline r match {
case ReEmpty => x
case rc: ReCons[X, _, _] => rc.n2
case rc: ReCons[_, _, _] => getRemapped(x, rc.rest).asInstanceOf[Remapped[X, R]]
}
type RemapAtoBAndCtoD = ReCons["a", "b", ReCons["c", "d", ReEmpty.type]]
val remapping: RemapAtoBAndCtoD = ReCons("a", "b", ReCons("c", "d", ReEmpty))
val remapped2: ("b", "d", "f") = (
getRemapped("a", remapping),
getRemapped("c", remapping),
getRemapped("f", remapping)
) // (b,d,f)
//myList.map[[X <: String] =>> Remapped[X, RemapAtoBAndCtoD]]([X <: String] => (x: X) => getRemapped(x, remapping))
//[error] |Found: Object with PolyFunction {...}
//[error] |Required: PolyFunction{apply: [t](x: t): A.Remapped[t, A.RemapAtoBAndCtoD]}
//https://github.com/milessabin/shapeless/pull/901
我目前正在尝试感受一下 Scala 3/dotty 中的新特性。所以我想重做一些我以前用无形尝试过的东西。给定一个缩小的字符串类型的异构列表(在 shapeless 中它将是 "a" :: "c" :: "f" :: HNil
并且据我所知,在 dotty 中,可以使用元组 ("a", "c", "f")
),我想根据一些映射替换类型.例如考虑以下伪代码:
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")
为此,我想出了以下代码。重新映射单个缩小的 String 类型正在工作。但我也无法让它与元组一起工作:
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
我得到的编译错误是 Type argument s does not conform to upper bound String
在以下行中:
s match
case String => Remapped[s, R] *: AllRemapped[rest, R]
我使用了 dotty 版本 0.18.1-RC1
,因为它是 Scastie 上最新可用的版本。这是您可以试验的 link:https://scastie.scala-lang.org/BKzhEV7PRiKyfQ3CE2vjww
这是不支持的吗,有没有办法实现这个,即如何进一步限制匹配类型内的类型模式中的类型(我试过case (s <: String) *: rest =>
,但编译器失败并出现错误:scala.MatchError: Parens(Ident(s)) (of class dotty.tools.dotc.ast.untpd$Parens)
)?是否还有更好的方法来实现我总体上尝试做的事情(在 dotty 的当前能力范围内,例如 erased
和 inline
)?
尝试引入辅助类型并将其用作类型模式
type Hlp[X <: String, Rest <: Tuple] = X *: Rest
type AllRemapped[T <: Tuple, R <: Remapping] <: Tuple = T match {
case Unit => Unit
case Hlp[s, rest] => Remapped[s, R] *: AllRemapped[rest, R]
}
inline
和 erased
不适用于 type
。
实际上对于元组的映射有标准类型Tuple.Map
虽然目前在 0.18.1-RC1 中我不能让它工作
type AllRemapped[T <: Tuple, R <: Remapping] = Tuple.Map[T, [X <: String] =>> Remapped[X, R]]
//Type argument [X <: String] => A.Remapped[X, R] does not conform to upper bound [_] => Any
用inline
你可以做到
inline def g(x: "a" | "c" | "f") <: String = inline x match {
case "a" => "b"
case "c" => "d"
case "f" => "f"
}
g("a"): "b"
g("c"): "d"
g("f"): "f"
// g("x") // doesn't compile
尝试
sealed 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]
}
inline def getRemapped[X <: String & Singleton, R <: Remapping] erased (x: X, r: R) <: String = inline r match {
case ReEmpty => x
case rc: ReCons[X, _, _] => rc.n2
case rc: ReCons[_, _, _] => getRemapped(x, rc.rest).asInstanceOf[Remapped[X, R]]
}
type RemapAtoBAndCtoD = ReCons["a", "b", ReCons["c", "d", ReEmpty.type]]
val remapping: RemapAtoBAndCtoD = ReCons("a", "b", ReCons("c", "d", ReEmpty))
val remapped2: ("b", "d", "f") = (
getRemapped("a", remapping),
getRemapped("c", remapping),
getRemapped("f", remapping)
) // (b,d,f)
//myList.map[[X <: String] =>> Remapped[X, RemapAtoBAndCtoD]]([X <: String] => (x: X) => getRemapped(x, remapping))
//[error] |Found: Object with PolyFunction {...}
//[error] |Required: PolyFunction{apply: [t](x: t): A.Remapped[t, A.RemapAtoBAndCtoD]}
//https://github.com/milessabin/shapeless/pull/901