Scala 柯里化与部分应用函数

2023-12-03

我意识到这里有几个问题what柯里化和部分应用函数是,但我问的是它们有何不同。作为一个简单的例子,下面是一个用于查找偶数的柯里化函数:

def filter(xs: List[Int], p: Int => Boolean): List[Int] =
   if (xs.isEmpty) xs
   else if (p(xs.head)) xs.head :: filter(xs.tail, p)
   else filter(xs.tail, p)

def modN(n: Int)(x: Int) = ((x % n) == 0)

因此,您可以编写以下内容来使用它:

val nums = List(1,2,3,4,5,6,7,8)
println(filter(nums, modN(2))

返回:List(2,4,6,8)。但我发现我可以用这种方式做同样的事情:

def modN(n: Int, x: Int) = ((x % n) == 0)

val p = modN(2, _: Int)
println(filter(nums, p))

它还返回:List(2,4,6,8).

所以我的问题是,两者之间的主要区别是什么,什么时候会使用其中一种而不是另一种?这个例子是否过于简单,无法说明为什么要使用其中一个而不是另一个?


语义差异已经得到很好的解释Plasty Grove 链接的答案.

但就功能而言,似乎没有太大区别。让我们看一些例子来验证这一点。首先,一个正常的功能:

scala> def modN(n: Int, x: Int): Boolean = ((x % n) == 0)
scala> modN(5, _ : Int)
res0: Int => Boolean = <function1>

所以我们得到了部分应用的<function1>这需要一个Int,因为我们已经给了它第一个整数。到目前为止,一切都很好。现在进行柯里化:

scala> def modNCurried(n: Int)(x: Int): Boolean = ((x % n) == 0)

使用这种表示法,您会天真地期望以下内容能够工作:

scala> modNCurried(5)
<console>:9: error: missing arguments for method modN;
follow this method with `_' if you want to treat it as a partially applied function
          modNCurried(5)

So the 多参数列表符号似乎并没有立即创建一个柯里化函数(假设是为了避免不必要的开销),而是等待您明确声明您希望它柯里化(该符号有一些其他优点以及):

scala> modNCurried(5) _
res24: Int => Boolean = <function1>

这与我们之前得到的完全相同,因此除了符号之外没有任何区别。另一个例子:

scala> modN _
res35: (Int, Int) => Boolean = <function2>

scala> modNCurried _
res36: Int => (Int => Boolean) = <function1>

这演示了部分应用“正常”函数如何产生一个接受所有参数的函数,而部分应用具有多个参数列表的函数如何创建一个函数链,每个参数列表一个其中,都返回一个新函数:

scala> def foo(a:Int, b:Int)(x:Int)(y:Int): Int = a * b + x - y
scala> foo _
res42: (Int, Int) => Int => (Int => Int) = <function2>

scala> res42(5)
<console>:10: error: not enough arguments for method apply: (v1: Int, v2: Int)Int => (Int => Int) in trait Function2.
Unspecified value parameter v2.

正如你所看到的,因为第一个参数列表foo有两个参数,柯里化链中的第一个函数有两个参数。


总之,就功能而言,部分应用函数与柯里化函数并没有真正的不同。鉴于您可以将任何函数转换为柯里化函数,这一点很容易得到验证:

scala> (modN _).curried
res45: Int => (Int => Boolean) = <function1

scala> modNCurried _
res46: Int => (Int => Boolean) = <function1>

后记

Note:你的例子的原因println(filter(nums, modN(2))之后不带下划线即可工作modN(2)似乎 Scala 编译器只是简单地假设下划线是为了方便程序员。


添加:正如 @asflierl 正确指出的那样,Scala 在部分应用“正常”函数时似乎无法推断类型:

scala> modN(5, _)
<console>:9: error: missing parameter type for expanded function ((x$1) => modN(5, x$1))

而该信息可用于使用多参数列表表示法编写的函数:

scala> modNCurried(5) _
res3: Int => Boolean = <function1>

这个答案展示了这如何非常有用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Scala 柯里化与部分应用函数 的相关文章

  • Source.getLines 中的默认参数错误 (Scala 2.8.0 RC1)

    假设我运行 Scala 2 8 0 RC1 以下 scala 代码应该打印出文件 c hello txt 的内容 for line lt Source fromPath c hello txt getLines println line 但
  • 使用 Spark DataFrame 获取组后所有组的 TopN

    我有一个 Spark SQL DataFrame user1 item1 rating1 user1 item2 rating2 user1 item3 rating3 user2 item1 rating4 如何按用户分组然后返回TopN
  • Scala Tuple2Zipped 与 IterableLike zip

    两种实现有什么区别 这个比那个好吗 有一篇博客文章说 Tuple2Zipped 性能更好 但没有提供原因 并且查看源代码我没有看到差异 val l1 List 1 2 3 val l2 List 5 6 7 val v1 l1 zip l2
  • 使用spark phoenix从表中读取rdd分区号为1

    当我运行我的火花代码时 val sqlContext spark sqlContext val noact table primaryDataProcessor getTableData sqlContext zookeeper table
  • 对 Scala Not Null 特征的库支持

    Notice 从 Scala 2 11 开始 NotNull已弃用 据我了解 如果您希望引用类型不可为空 则必须混合魔法NotNull特征 编译器会自动阻止你输入null 可以值在里面 看到这个邮件列表线程 http www nabble
  • 在 IntelliJ 中运行 Spark 字数统计

    我花了几个小时浏览 You Tube 视频和教程 试图了解如何在 Scala 中运行 Spark 字数统计程序 并将其转换为 jar 文件 我现在完全糊涂了 我运行了 Hello World 并且了解了如何在 Apache spark sp
  • 为什么在 Scala 中函数类型需要以单独的参数组传递到函数中

    我是 scala 新手 我用两种方式编写了相同的代码 但我对两种方式有点困惑 在第二种方式中 f 的参数类型是自动派生的 但在 type1 中 scala 编译器无法执行相同的操作 我只是想了解这背后的想法是什么 Type1 给出编译错误
  • 如何使用 log4j 自定义附加程序在 HDFS 上创建日志?

    Overview 我们希望使用 log4j 记录 Spark 作业活动 并将日志文件写入 HDFS Java 8 Spark 2 4 6 Scala 2 1 2 Hadoop 3 2 1 我们无法找到本地 apache log4j 附加程序
  • 向 Scala Swing Panel 添加标签时出现类型不匹配错误

    我有这个课程扩展FlowPanel我正在尝试向其中添加标签 import java awt Label Color import scala swing import scala util Random class MyPanel exte
  • 在 Scala 中调用 WebSocket 中的方法

    我是 scala Play 框架和 Akka 的新手 我的函数定义为 def socket WebSocket accept String String request gt ActorFlow actorRef out gt MyWebS
  • Spark中如何获取map任务的ID?

    Spark中有没有办法获取map任务的ID 例如 如果每个映射任务都调用用户定义的函数 我可以从该用户定义的函数中获取该映射任务的 ID 吗 我不确定您所说的地图任务 ID 是什么意思 但您可以使用以下方式访问任务信息TaskContext
  • 使用 Scala 进行网页抓取 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 如何访问 Scala XML 中的父元素

    The scala xml包表示带有标记树节点的 XML 但是这棵树在 Scala 2 7 中是单向的吗 因为似乎没有办法访问Elem给定的父级Elem 这似乎同样适用于父母Document 例如 在 XOM 中你有getParent an
  • 如何在Java 8中实现Elvis运算符?

    我有一个经典的 Elvis 运算符 案例 其中我调用每个可能返回 null 的方法并将它们链接在一起 thing nullableMethod1 a nullableMethod2 b nullableMethod3 在 Java 8 中
  • 为什么我们需要 scala 中的特征?

    所以 我试图制作一个 Finagle 服务器 与哨兵交谈 不重要 并偶然发现了一个案例 我需要从两个继承classes 不是特质 同时 我们称它们为class SentryHandler extends Handler and class
  • 是否有适用于 Haskell 或 Scala 等函数式语言的 LL 解析器生成器?

    我注意到明显缺乏用函数式语言创建解析器的 LL 解析器 我一直在寻找但没有成功的理想发现是为 ANTLR 风格的 LL 语法生成 Haskell 解析器 语法的模小数重新格式化 并且令我惊讶的是 每个最后一个解析器生成器都具有函数我发现的语
  • 到底什么是单例类型?

    什么是单例类型 有什么应用和影响 我们非常欢迎示例 更欢迎外行术语 如果将类型视为一组值 则值的单例类型x是仅包含该值的类型 x 用法示例 模式匹配 case Foo type检查匹配的对象是否与Foo using eq where cas
  • sbt 项目构建中的多个目标目录

    我有一个这样结构的 sbt 项目 build sbt project build properties plugins sbt src main java smcho App java test java smcho AppTest jav
  • 为什么你需要创建这些 json 读/写,而在 java 中你不需要创建这些 json 读/写?

    如果我错了 请纠正我 但是当使用 Java 和 Spring MVC 时 您不必创建这些额外的类来将 Java 类映射到 JSON 以及将 JSON 映射到类 为什么必须在 Play with Scala 中执行此操作 和Scala有关系吗
  • Spark Scala 相当于 SKEW 连接提示

    Spark SQL 有一个可用的倾斜提示 请参阅here https docs databricks com spark latest spark sql skew join html relation columns and skew v

随机推荐