我试图设计一个没有固定在它可以作为值支持的类型的DSL。
下面我尝试使用Value
类型类来实现此目的。虽然它会出现在预期的应用程序中,但它没有行为。
trait Value[T]
object Value {
implicit object IntIsValue extends Value[Int]
implicit object StringIsValue extends Value[String]
}
DSL由价值术语和应用术语组成:
abstract class Term[T: Value]
case class ValueTerm[T: Value](x: T) extends Term[T]
case class AppTerm[Arg: Value, T: Value](fun: Arg => T, arg: Term[Arg]) extends Term[T]
评估功能是我编译问题的地方:
def eval[T: Value](term: Term[T]): T = {
term match {
case ValueTerm(x) => x
case AppTerm(fun, arg) => fun(eval(arg)) // doesn't compile
}
}
这是我得到的代表性编译错误:
Error:(14, 40) could not find implicit value for evidence parameter of type A$A354.this.Value[Any]
case AppTerm(fun, arg) => fun(eval(arg))
^
所以编译器认为arg
是Term[Any]
并且不知道它是Value
的实例。
我知道我可以通过从Value
删除eval
约束来避免这种情况。但是,我失去了Value
的行为,我可能想在eval
中使用:
def eval[T](term: Term[T]): T -- loses behaviour of Value typeclass
所以我的问题是
以下是DSL的一些用法:
val i41: Term[Int] = ValueTerm(41)
val i42: Term[Int] = AppTerm(fun = (_: Int) + 1, arg = i41)
val theAnswer: Term[String] = AppTerm(fun = "The answer is " ++ (_: Int).toString, arg = i42)
eval(i41)
eval(i42)
eval(theAnswer)
答案 0 :(得分:1)
问题在于这些术语带有必要的含义,但这样它们不会自动成为隐式范围的一部分。快速解决方法是向AppTerm
添加一个公开Value[Arg]
的方法。然后,您可以明确地将其传递给eval
。
def eval[T: Value](term: Term[T]): T = {
term match {
case ValueTerm(x) => x
case t @ AppTerm(fun, arg) => fun(eval(arg)(t.implicitArg))
}
}
但是,您可能会将此视为您希望以不同方式设计解决方案的标志。例如,您在Value
中捕获隐式Term
,然后在eval
中捕获Term
并且再次隐含Value
似乎很危险}。因此,可以传递与Value
中捕获的eval
不同的Term
到obj.results
。