scala 如何处理高阶类型的元组?

r8uurelv  于 2023-04-30  发布在  Scala
关注(0)|答案(1)|浏览(117)

当然是Scala 3。Scala 2的Tuple设置会阻止我尝试这个。
我正在尝试编写一个通用的解析器库与可插拔的算法。所以,当你写语法的时候,它会被转换成抽象语法树,然后这些抽象语法树会被馈送到你想使用的任何算法中,由算法来决定它如何解析输入。
例如,我有这些数据类,它们都扩展了ParseExpr[+T]

case class Term[T](t: T) extends ParseExpr[T] // a single terminal
case class NonTerm[T](name: String) extends ParseExpr[T] // a non-terminal
      // I also store the type of the non-terminal, but it's ugly

case class Alt[T](ps: List[Pexpr[T]]) extends ParseExpr[T] // a list of alternate ParseExprs
case class Cat[?](ps: ?) extends ParseExpr[?] // a sequence of ParseExprs

一切都很好,除了最后一个。Scala解析器组合子处理等价的AltCat的方式是将它们二进制化。换句话说,在AltCat中只能有两个ParseExpr,但它们也可以是AltCat,因此可以用Cat(Cat(p, q), r)构建相当于p ~ q ~ r的东西。
我正在实现一个算法,当解析器没有二进制化时,它的速度要快得多,所以我尝试创建一个Cat的版本,它可以使用任意数量的ParseExpr。当然,问题是解析器序列的结果是一个(异构的)值序列。所以我想我可以让事情完全通用,并使用新的Scala 3 Tuple
这是我尝试的:

case class Cat[Ts <: Tuple](ps: Map[Ts, ParseExpr]) extends ParseExpr[Ts]

我认为这是说Cat接受ParseExpr s的元组,每个元组都有自己的类型,并按顺序生成给定类型的元组。太棒了但我什么也做不了。
首先,我必须将Cat[Ts](pes: Map[Ts, ParseExpr])转换为实际的解析器。为此,我必须将每个ParseExpr转换为Parser。所以我尝试在Tuple上使用map

parseExpr match
  case Cat(ps) => ps.map([t] => (pe: t) => parserFor(pe)) // should return Map[Ps, Parser]

但是无论我怎么做,我都不能让东西进行类型检查。
我是不是咬掉了太多,高阶类型的Tuple比它们的价值更麻烦,还是我错过了一些基本的东西?

2ul0zpep

2ul0zpep1#

如果你开始使用HLists(也就是元组)执行类型级计算(对Tuple.Map这样的元组的操作是根据匹配类型定义的),你应该继续使用

  • 匹配类型,或
  • 类型类。

您应该做好准备,使用匹配类型(尤其是在值级别上)可能很棘手,有许多限制,并且类型推断相当弱
How to prove that Tuple.Map[H *: T, F] =:= (F[H] *: Tuple.Map[T, F]) in Scala 3
Tuples in Scala 3 Compiler Operations for Typeclass Derivation
Type-level filtering tuple in Scala 3
How to get match type to work correctly in Scala 3
Scala 3: typed tuple zipping
scala 3 map tuple to futures of tuple types and back
Express function of arbitrary arity in vanilla Scala 3
Shapeless3 and annotations
Scala 3. Implementing Dependent Function Type
In Scala 3, how to replace General Type Projection that has been dropped?
What does Dotty offer to replace type projections?
但是无论我怎么做,我都不能让东西进行类型检查。
恐怕这不是对你所做的和你所犯错误的恰当描述。您应该始终准备MCVE,然后我们可以考虑您的特定编译错误。此外,您还应该用示例输入和理想输出来补充MCVE。
下面的代码似乎可以编译

trait Parser[T]

sealed trait ParseExpr[T]
case class Term[T](t: T) extends ParseExpr[T]
case class NonTerm[T](name: String) extends ParseExpr[T]
case class Alt[T](ps: List[ParseExpr[T]]) extends ParseExpr[T]
case class Cat[Ts <: Tuple](ps: Tuple.Map[Ts, ParseExpr]) extends ParseExpr[Ts]

def parserFor[T](pe: ParseExpr[T]): /*ParserFor[T]*/Parser[T] = ???

type ParserFor[T /*<: ParseExpr[?]*/] /*<: Parser[?]*/ = T match
  case ParseExpr[t] => Parser[t]

type Ps <: Tuple
val parseExpr: ParseExpr[Ps] = ???
val res = parseExpr match
  case Cat(ps) => ps.map[ParserFor]([pe_t /*<: ParseExpr[?]*/] => (pe: pe_t) => pe match
    case pe: ParseExpr[t] => parserFor[t](pe)
  )

def test(using Tuple.Map[Tuple.Map[Ps, ParseExpr], ParserFor] =:= Tuple.Map[Ps, Parser]): Unit =
  res: Tuple.Map[Ps, Parser]

Scala 3.2.2

相关问题