gpt4 book ai didi

scala - 确定表达式的值在编译时是否已知

转载 作者:行者123 更新时间:2023-12-04 20:42:27 24 4
gpt4 key购买 nike

假设我想创建一个 NonZero键入以便我的整数除法函数是总计:

def div(numerator: Int, denominator: NonZero): Int =
numerator / denominator.value

我可以通过创建 NonZero 来实现这一点具有私有(private)构造函数的类:
class NonZero private[NonZero] (val value : Int) { /*...*/ }

还有一个辅助对象来保存 Int => Option[NonZero]构造函数和 unapply所以它可以用于 match表达式:
object NonZero {
def build(n:Int): Option[NonZero] = n match {
case 0 => None
case n => Some(new NonZero(n))
}
def unapply(nz: NonZero): Option[Int] = Some(nz.value)
// ...
}
build对于运行时值很好,但必须做 NonZero.build(3).get因为文字感觉很丑。

使用宏,我们可以定义 apply only for literals , 所以 NonZero(3)有效,但 NonZero(0)是编译时错误:
object NonZero {
// ...
def apply(n: Int): NonZero = macro apply_impl
def apply_impl(c: Context)(n: c.Expr[Int]): c.Expr[NonZero] = {
import c.universe._
n match {
case Expr(Literal(Constant(nValue: Int))) if nValue != 0 =>
c.Expr(q"NonZero.build(n).get")
case _ => throw new IllegalArgumentException("Expected non-zero integer literal")
}
}
}

然而,这个宏没有它可能有用,因为它只允许文字,而不是编译时常量表达式:
final val X: Int = 3
NonZero(X) // compile-time error

could pattern match on Expr(Constant(_)) 在我的宏中,但是 NonZero(X + 1) 呢? ?我宁愿不必实现我自己的 scala 表达式求值器。

是否有帮助程序或一些简单的方法来确定在编译时是否知道给定宏的表达式的值(C++ 会调用 constexpr )?

最佳答案

如果忽略宏,那么在 Scala 中,编译时只存在类型,运行时只存在值。您可以在编译时使用类型级技巧将数字编码为类型,例如Type Level Programming in Scala

这是上述Peano算术示例的简化版本。首先,我们定义了一个类型类,它显示了某些类型如何转换为整数。

@annotation.implicitNotFound("Create an implicit of type TValue[${T}] to convert ${T} values to integers.")
final class TValue[T](val get: Int) extends AnyVal

然后,我们定义 Peano 'zero' 类型并展示它如何转换为运行时整数 0:
case object TZero {
implicit val tValue: TValue[TZero.type] = new TValue(0)
}

然后是 Peano 'successor' 类型以及它如何转换为运行时整数 1 + 先前值:
case class TSucc[T: TValue]()
object TSucc {
implicit def tValue[TPrev](implicit prevTValue: TValue[TPrev]): TValue[TSucc[TPrev]] =
new TValue(1 + prevTValue.get)
}

然后测试安全划分:
object Test {
def safeDiv[T](numerator: Int, denominator: TSucc[T])(implicit tValue: TValue[TSucc[T]]): Int =
numerator / tValue.get
}

尝试一下:
scala> Test.safeDiv(10, TZero)
<console>:14: error: type mismatch;
found : TZero.type
required: TSucc[?]
Test.safeDiv(10, TZero)
^

scala> Test.safeDiv(10, TSucc[String]())
<console>:14: error: Create an implicit of type TValue[String] to convert String values to integers.
Test.safeDiv(10, TSucc[String]())
^

scala> Test.safeDiv(10, TSucc[TZero.type]) // 10/1
res2: Int = 10

scala> Test.safeDiv(10, TSucc[TSucc[TZero.type]]) // 10/2
res3: Int = 5

正如您可以想象的那样,这可能会很快变得冗长。

关于scala - 确定表达式的值在编译时是否已知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52857429/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com