【问题标题】:how to simplify scala's function literal like this?如何像这样简化scala的函数文字?
【发布时间】:2011-01-18 14:53:07
【问题描述】:

我是 scala 的新手,正在尝试编写一个函数文字来检查给定整数是否为奇数。 我的第一次尝试是:

val isOdd = (x:Int) => (x & 1) == 1

效果很好,而且由于参数 x 在这个函数字面量中只出现一次,我很想使用“_”符号来进一步简化它,如下所示:

val isOdd = ((_:Int) & 1 ) == 1

但是这次编译器抱怨:

警告:使用 `==' 比较新对象总是会产生错误
val isOdd = ((_:Int) & 1 ) == 1

这个警告是什么意思?为什么编译器将((_ :Int) & 1) 识别为新对象而不是产生值的按位运算?有没有办法使用“_”符号来编写这个函数字面量?

【问题讨论】:

  • 只需使用:val odd = ! even (_:Int)

标签: scala function-literal


【解决方案1】:

问题基本上是Scala需要区分

val isOdd = ((_:Int) & 1 ) == 1

您希望等号右侧的所有内容都是 lambda,并且

val result = collection.map( _ + 1 )

您只希望括号内的内容是 lambda

Scala 已决定,当您使用下划线创建 lambda 时,它将选择最里面的一组括号作为该 lambda 的边界。有一个例外:(_:Int) 不算在最里面的括号,因为它的目的只是将他们的类型声明与_ 占位符分组。

因此:

val isOdd = ((_:Int) & 1 ) == 1
            ^^^^^^^^^^^^^^
            this is the lambda

val result = collection.map( _ + 1 )
                            ^^^^^^^
                            this is the lambda

val result = collection.map(( _ + 1) / 2)
                            ^^^^^^^^
                            this is the lambda
                            and the compiler can't infer the type of the _

val result = somemap.map(( _ + 1) / 2 * _)
                         ^^^^^^^^
                         this is an inner lambda with one parameter
                         and the compiler can't infer the type of the _
                         ^^^^^^^^^^^^^^^^^
                         this is an outer lambda with one parameter

最后一种情况可以让你做类似的事情

_.map(_ + 1)

并将其翻译成

x => x.map( y=> y + 1 )

【讨论】:

  • 感谢澄清有关 lambda 表达式边界的规则!
【解决方案2】:

只是稍微作弊:

val isOdd = (_: Int) % 2 == 1

:-)

【讨论】:

  • +1 这不是作弊。事实上,我认为使用& 是过早的优化。 % 形式更清晰,任何值得加盐的编译器(或者可能是 JIT)都会看到 % 2 并将其更改为 & 1,如果它在该操作环境中实际上更快的话。
  • 我同意一般来说我们应该把这种优化留给编译器;但在这里我实际上想了解这个 lambda 事情背后的基本原理。再次感谢您澄清有关 lambda 的括号规则:)
  • @KenBloom 我会坚持认为,对工作使用最好的算法并不是过早的优化,它只是很好的编程,我厌倦了人们使用这种理由来编写慢代码(一般来说,这是一个微型示例,其中差异可能可以忽略不计)。你可以用另一种机制更优雅地完成它,这与风格有关,与优化无关。
  • 请注意,这不适用于负数,而 & 可以。
【解决方案3】:

你去吧:

val isOdd = ((_: Int) & 1) andThen (1 ==)

【讨论】:

    【解决方案4】:

    Scala 正在做的是:

    • 它看到((_:Int) & 1 )并创建一个(Int) => Int类型的对象,即一个函数。
    • 然后应用比较运算符 == 将此函数与值 1 进行比较

    一个函数不等于1。因此结果是false,所以你的代码相当于:

    val isOdd = false
    

    您可以做的是创建另一个匿名函数来执行 == 1 部分的计算。这很丑:

    val isOdd = ((_: Int) & 1)(_: Int) == 1
    

    这相当于更冗长(也许更容易理解):

    val isOdd = (x: Int) => 1 == ((_: Int) & 1)(x)
    

    【讨论】:

    • 我不推荐这两种解决方案——它们都更复杂,而且它们都创建了一个额外的、不必要的 lambda。坚持val isOdd = (x:Int) => (x & 1) == 1
    • 当然!但是 OP 特别询问是否有任何方法可以只使用“_”来编写他的“isOdd”lambda。我不认为我们在这里讨论好的风格。
    • 你错过了val isOdd = ((_: Int) & 1) andThen (_ == 1)。 :-)
    • 是的!幸运的是@Debilski 发布了这个!
    【解决方案5】:

    另一种方法

    val isOdd = (_:Int).&(1) == 1
    

    【讨论】:

      猜你喜欢
      • 2019-10-10
      • 2011-05-15
      • 2019-01-25
      • 2014-07-20
      • 1970-01-01
      • 2015-03-28
      • 1970-01-01
      • 2011-11-17
      相关资源
      最近更新 更多