Scala 在不更改函数签名的情况下使参数变懒?

Scala 在不更改函数签名的情况下使参数变懒?,scala,lazy-evaluation,Scala,Lazy Evaluation,鉴于: 调用f(55,yFn)将导致f的评估,由y打印输出显示 scala> def f(x: Int, y: Int): Int = | if(x == 55) x else y f: (x: Int, y: Int)Int scala> def yFn: Int = {println("y"); 42} yFn: Int f的签名如何保持不变: (Int,Int)=>Int 但是,如果不按名称设置y参数,是否会对y进行惰性评估 scala> f(55,

鉴于:

调用
f(55,yFn)
将导致
f
的评估,由
y
打印输出显示

scala> def f(x: Int, y: Int): Int = 
     |   if(x == 55) x else y
f: (x: Int, y: Int)Int

scala> def yFn: Int = {println("y"); 42}
yFn: Int
f
的签名如何保持不变:

(Int,Int)=>Int


但是,如果不按名称设置
y
参数,是否会对
y
进行惰性评估

scala> f(55, yFn)
y
res0: Int = 55
f
的签名具有
Int
,而不是
=>Int
,但是调用
f(55,yFn)
将简单地被
if(55==55)55 else yFn
替换,它将不计算
yFn

从这一点可以看出,任何不查看其参数结构的宏都有效地按名称使用它们;如果要确保参数只计算一次,则需要将其分配给局部变量:
q“{val x=$x;if(x==55)x else$y}”


但是,如果您想将
f
转换为对象而不是方法,这将丢失,因为生成的类的
apply
方法不是宏(它不能是宏;宏不能实现抽象方法(当然也不能覆盖具体方法))。

您不能,除非有某种宏魔法允许它。即使我强烈建议不要这样做,因为这将意味着明确违反签名合同和语言规范。即使不建议,我很想看到这样一个宏的实现——这是我自己的学习。我甚至想不出用宏来实现它的方法。@m-z你可以,如果x在编译时是已知的,就像他的例子中一样,看看我的答案。我不确定能不能再多一些done@GiovanniCaporaletti我已经把我的评论变成了一个答案,来进一步扩展一下。嗨,亚历克赛,谢谢你的回答。您能提供使用此代码所需的导入吗?
import language.experimental.macros
import scala.reflect.macros.whitebox.Context

object Macros {
  def f(x: Int, y: Int): Int = macro fImpl

  def fImpl(c: Context)(x: c.Expr[Int], y: c.Expr[Int]): c.Expr[Int] = {
    import c.universe._
    c.Expr(q"if ($x == 55) $x else $y")
  }
}