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 解析器组合器处理等效的
Alt
和 Cat
的方式是将它们二值化。换句话说,您只能在 ParseExpr
或 Alt
中有两个 Cat
,但它们也可以是 Alt
和 Cat
,因此您可以用 p ~ q ~ r
构建 Cat(Cat(p, q), r)
的等价物.
我正在实现一种算法,当解析器没有二值化时,它的速度要快得多,所以我正在尝试创建一个
Cat
的版本,它需要任意数量的 ParseExpr
s。当然,问题是一系列解析器的结果是一个(异构的)值序列。所以我想我可以使事情完全通用并使用新的 Scala 3Tuple
.
这是我尝试过的:
case class Cat[Ts <: Tuple](ps: Map[Ts, ParseExpr]) extends ParseExpr[Ts]
我认为这说明的是
Cat
采用一个 ParseExpr
的元组,每个元组都有自己的类型,并按顺序生成给定类型的元组。这很棒。除了我不能用它做任何事。
首先,我必须将
Cat[Ts](pes: Map[Ts, ParseExpr])
转换为实际的解析器。为此,我必须将每个 ParseExpr
转换为 Parser
。所以我试着map
超过Tuple
:
parseExpr match
case Cat(ps) => ps.map([t] => (pe: t) => parserFor(pe)) // should return Map[Ps, Parser]
但是无论我怎么做,我都无法进行类型检查。
我是不是贪多嚼不烂,
Tuple
高阶类型的麻烦多于它们的价值,还是我在这里遗漏了一些基本的东西?
如果你开始使用 HLists aka Tuples 执行类型级计算(像
Tuple.Map
这样的元组操作是根据匹配类型定义的)你应该继续使用
匹配类型,或
类型类。
您应该准备好使用匹配类型(尤其是在值级别)可能会很棘手,有很多限制,并且类型推断非常薄弱
如何在 Scala 3 中证明 `Tuple.Map[H *: T, F] =:= (F[H] *: Tuple.Map[T, F])`
Scala 3 中,如何替换被丢弃的General Type Projection?
但是无论我怎么做,我都无法进行类型检查。
恐怕这不是对您正在做的事情以及您遇到的错误的正确描述。您应该始终准备 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