【问题标题】:Scala: How to define a function whose input is (f, args) and whose output is f(args)?Scala:如何定义一个输入为 (f, args) 且输出为 f(args) 的函数?
【发布时间】:2014-04-15 09:52:25
【问题描述】:

如何在 Scala 中定义一个函数 myEval(f, args),它将另一个函数 f 和参数 args 作为输入,其输出是 f(args)

我不希望myEvalf 的arity 或参数类型有任何先验知识。

为什么这很有用?这是解决实现通用timeMyFunction(f, args) 方法问题的一种方法。如果有办法通过某种惰性 val 构造来做到这一点,那也会很有趣。

编辑:在this question 中解释了实现计时方法的更好方法。通过调用timeMyFunction( { f(args) } ),函数调用被包装在匿名函数Unit => Unit 中。所以timeMyFunction只需要取0-arity函数即可。

编辑 2:请参阅 Dirk 的回答,了解通过引用传递 f 来避免匿名函数的更有效方法。

所以我提出这个问题的理由现在纯粹是我的 Scala 教育。

【问题讨论】:

  • 答案不多,但通常是 timeMyFunction is written in a bit different way(是的,它适用于任意数量的函数)
  • 我尝试编写 timeMyFunction 是基于您发布的链接,但您必须为每个 arity 制作不同的版本,至少以我幼稚的方式。
  • 而不是为其指定函数和参数,您应该提供一个完整的块(例如:而不是timeMyFunction(f, args)timeMyFunction(f(args)),其中 timeMyFunction 签名在 om-nom-nom 提供的链接中)
  • 谢谢!所以看起来我将 f 包装在一个不带参数的匿名函数中,然后我可以使用 time 函数。

标签: scala generics lazy-evaluation


【解决方案1】:

在大多数情况下,Scala 标准库无法帮助您泛化超过 arity,但 Shapeless 非常适合这一点。以下是在 Shapeless 1.2.4 中编写函数的方法:

import shapeless._

def foo[F, P <: Product, A <: HList, R](f: F, p: P)(implicit
  fl: FnHListerAux[F, A => R],
  pl: HListerAux[P, A]
): R = fl(f)(pl(p))

然后:

scala> foo((i: Int, s: String) => s * i, (3, "a"))
res0: String = aaa

它看起来很复杂,但本质上你只是说你需要证据证明某个任意数量的函数f 可以从异构列表A 转换为单参数函数到结果R ,并且元组P可以转换为同类型的异构列表。

【讨论】:

  • 有道理,无形库看起来很强大,但我不明白为什么 Scala 不将函数的参数视为元组,例如,所有函数都具有函数类型[元组]?
  • 是的,这是个好问题。我希望 Scala 在这方面能够效仿 OCaml、Haskell 等。
  • @expz: 长期以来,统一参数列表和元组一直是 Martin Odersky 的愿望清单,但它是 a) 低优先级和 b) 很难以一种既倒退的方式实现- 兼容且不损害平台集成。例如,如果所有重载都采用一个元组,Java 将如何看待重载的 Scala 方法?
【解决方案2】:

使用 pass-by-name 的替代方法是:

def timeIt[T](thunk: =>T): T = {
    // ... set-up the timer 
    val answer: T = thunk
    // ... evaluate the result of the timer
    answer  // in case, you need the result and want the timing to
}           // happen just as a side-effect

timeIt(someFunction(someArg1, ...))

虽然这看起来好像会直接调用someFunction,但实际上并没有,因为timeIt 采用“按名称”的参数,即,scala 编译器生成一个隐藏的闭包,它执行调用,当实际timeIt 本身需要值。

由于“按名称传递”约定的开销,此变体可能会引入一些时序噪声。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-30
    • 2011-04-04
    • 2019-10-05
    • 1970-01-01
    相关资源
    最近更新 更多