scala - 如何在 dotty 中编写带有缩小的 String 类型元组头的匹配类型模式?

标签 scala pattern-matching scala-3 dotty match-types

我目前正在尝试了解 Scala 3/dotty 中的新功能。所以我试图重做我之前尝试过的无形的东西。给定一个变窄的字符串类型的异构列表(在无形中是 "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 上最新的可用版本。这是您可以试验的链接:https://scastie.scala-lang.org/BKzhEV7PRiKyfQ3CE2vjww

这是否不受支持,有没有办法实现这一点,即如何进一步限制匹配类型内的类型模式中的类型(我尝试了 case (s <: String) *: rest => ,但编译器失败并出现错误: scala.MatchError: Parens(Ident(s)) (of class dotty.tools.dotc.ast.untpd$Parens) )?还有没有更好的方法来实现我的整体目标(在 dotty 的当前功能范围内,例如 erasedinline )?

最佳答案

尝试引入辅助类型并将其用作类型模式

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]
}
inlineerased不使用 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 [_$22] => 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$1: t): A.Remapped[t, A.RemapAtoBAndCtoD]}
//https://github.com/milessabin/shapeless/pull/901

关于scala - 如何在 dotty 中编写带有缩小的 String 类型元组头的匹配类型模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57835345/

相关文章:

Scala 3 方法在使用镜像时太大

scala - Dotty 提供什么来替换字体投影?

scala - 用于融合平台的 sbt 解析器

regex - 以逗号分隔行,仅当引号之间不包含逗号时

scala - 为什么 Play 框架不重新加载资源?

scala - 将 scalaz 析取集合转换为单个析取

Haskell:为什么模式匹配中不允许使用++?

scala - 使用 Scala 案例类作为事实上的映射

algorithm - 如何存储集合,快速找到相似的模式?

scala - 多态方法适用于 lambda 类型,但不适用于 Scala 3 中的类型通配符