具有非固定值类型集的 Scala DSL
Scala DSL with non-fixed set of value types
我正在尝试设计一个 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
.
的一个实例
我知道我可以通过从 eval
中删除 Value
约束来避免它。但是,然后我失去了 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)
问题是这些术语带有必要的隐式,但这样它们就不会自动成为隐式范围的一部分。一个快速修复方法是向 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))
}
}
但是,您可能会将此视为您想要设计稍微不同的解决方案的标志。例如,您在 Term
中捕获隐式 Value
,然后在 eval
中传入 Term
并再次传递隐式 [=14= 似乎很危险].因此,可以将与 Term
.
中捕获的 Value
不同的 eval
传递给 eval
我正在尝试设计一个 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
.
我知道我可以通过从 eval
中删除 Value
约束来避免它。但是,然后我失去了 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)
问题是这些术语带有必要的隐式,但这样它们就不会自动成为隐式范围的一部分。一个快速修复方法是向 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))
}
}
但是,您可能会将此视为您想要设计稍微不同的解决方案的标志。例如,您在 Term
中捕获隐式 Value
,然后在 eval
中传入 Term
并再次传递隐式 [=14= 似乎很危险].因此,可以将与 Term
.
Value
不同的 eval
传递给 eval