by-names参数如何在高阶函数中起作用?

时间:2013-04-18 23:02:18

标签: scala

我试图理解名字类型注释在高阶函数的上下文中的含义。这是一个例子:

object Test { 
  def apply[A, B](f: (=> A) => B, x: => A): B = f(x) 
  def const[A](ignored: A): Int = 1
  val res: Int = apply(const, ???)
}

const在其参数中是严格的(即它没有=>注释),所以为什么不强制它的参数(在这种情况下是???)并引发一个异常?

这里有没有描述语义的论文?

我在这里寻找权威的答案。

2 个答案:

答案 0 :(得分:5)

f函数中的参数applyFuncion1,它采用A类型的按名称调用参数并返回B。因此,f(x)不会评估按名称调用参数x,而是将其引用直接传递给f

了解res如下有用:

def res[C]: Int = apply[C, Int](const, ???)

在您的示例中,C将是非特定类型。现在,此行中const推断的类型参数是什么?它是=> C。很遗憾,您无法输入该参数:

def res[C]: Int = apply[C, Int](const[=> C], ???)  // illegal syntax

但你可以验证发生了什么:

def res[C]: Int = apply[C, Int](const[Nothing], ???)

给你

<console>:10: error: type mismatch;
 found   : Nothing => Int
 required: => C => Int
         def res[C]: Int = apply[C, Int](const[Nothing], ???)
                                              ^

此类型在const内显示为Function0[Int](因此Scala隐式将call-by-name或“thunk”参数视为不带参数的函数)。您可以再次验证这一点:

def const[A](ignored: A): Int = if (ignored.isInstanceOf[Function0[_]]) 1 else 0

现在Test.res会为您1(意味着ignored确实是Function0)。


因此,要以不同的方式回答问题,{​​{1}}有一个类型为const的急切参数,但这并不重要,因为A在您的示例中成为函数,并且你永远不会应用这个功能,因此永远不会执行A


Scala中有some debate why there is both一个“thunk”或无括号的函数和一个空的函数(???)。

答案 1 :(得分:0)

我正在打开另一个答案,因为你似乎还不清楚发生了什么:

  

通常严格属性是根据所应用的函数(在本例中为const)定义的,但您的解释非常关注实现以及如何构造const的参数。

我将使用不同的类型名重述您的对象:

object Test { 
  def apply[A, B](f: (=> A) => B, x: => A): B = f(x) 
  def const[C](ignored: C): Int = 1
  def res[A1]: Int = apply[A1, Int](const, ???)
}

现在,让我们用Function0交换名字参数,以突出隐藏“懒惰”的位置:

object Test { 
  def apply[A, B](f: (() => A) => B, x: () => A): B = f(x) 
  def const[C](ignored: C): Int = 1
  def res[A1]: Int = apply[A1, Int](const[() => A1], () => ???)
}

你知道,const的定义并不重要。重要的是x的{​​{1}}参数是按名称(或上一版本中的函数)。因此,apply使用函数参数 f(x)调用f,因此无论x的正文是什么,此时都不会对此进行评估。< / p>