我在定义类型构造函数时遇到问题,以废除Scala中部分类型应用程序的可怕类型lambda方法。给出:
trait Sys[S <: Sys[S]]
trait Expr[S <: Sys[S], +A] {
def value: A
}
import reflect.ClassTag
trait Proc[S <: Sys[S]] {
def attribute[A[~ <: Sys[~]]](key: String)
(implicit tag: ClassTag[A[S]]): Option[A[S]]
}
我们说我有这种方法:
def name[S <: Sys[S]](p: Proc[S]): String =
p.attribute[({type A[~ <: Sys[~]] = Expr[~, String]})#A]("name")
.fold("<unnamed>")(_.value)
我想把它定义为:
def name[S <: Sys[S]](p: Proc[S]): String =
p.attribute[XXX[String]]("name").fold("<unnamed>")(_.value)
问题是:如何定义类型构造函数XXX[A]
?
我的想法是:
type XXX[A] = ({type Ex[S <: Sys[S]] = Expr[S, A]})#Ex
但它只产生
<console>:52: error: type Ex takes type parameters
type XXX[A] = ({type Ex[S <: Sys[S]] = Expr[S, A]})#Ex
^
答案 0 :(得分:0)
我似乎找不到除了保持类型投影之外的解决方案,只是缩短了:
trait Ex[A] { type L[S <: Sys[S]] = Expr[S, A] }
def name[S <: Sys[S]](p: Proc[S]): String =
p.attribute[Ex[String]#L]("name").fold("<unnamed>")(_.value)
这仍然不是我想要的。我可以完全摆脱类型投射吗?
第二个想法是提供一种扩展方法:
implicit class RichProc[S <: Sys[S]](val `this`: Proc[S]) extends AnyVal {
def attrExpr[A](key: String)
(implicit tag: ClassTag[Expr[S, A]]): Option[Expr[S, A]] =
`this`.attribute[({type Ex[~ <: Sys[~]] = Expr[~, A]})#Ex](key)
}
def name[S <: Sys[S]](p: Proc[S]): String =
p.attrExpr[String]("name").fold("<unnamed>")(_.value)