如何解释用大括号括起来的函数值(菊石问题)

Posted

技术标签:

【中文标题】如何解释用大括号括起来的函数值(菊石问题)【英文标题】:How to interpret function value wrapped in curly braces (ammonite issue) 【发布时间】:2020-10-14 12:33:02 【问题描述】:

看完What is the formal difference in Scala between braces and parentheses, and when should they be used?,还是不知道怎么理解包裹的函数值。

考虑以下两个 REPL 会话:

@ val f =  (x: Int) =>
    x
    val y = x
    y
  
f: Int => Int = ammonite.$sess.cmd30$$$Lambda$1765/0x0000000801346840@24c7b944
@  (x: Int) =>
    x
    val y = x
    y
  
cmd31.sc:3: not found: value x
  val y = x
          ^
Compilation Failed

我有几个问题。

    为什么第一个 sn-p 编译而第二个不编译?在第一个 sn-p 中,编译器知道 ... 作为一个整体是一个函数值。在第二个 sn-p 中,只有 (x: Int) => \n x 部分是函数值(抱歉 \n 表示换行)。为什么? 关于 (x: Int) => \n ... ,什么时候解释为函数值,什么时候不解释? 大括号()是函数值的一部分,还是只有(...) => ...里面是函数值?如果它是它的一部分,表格是否有名称?例如,我认为(_ + _) 可以称为函数值的占位符语法。

更新:这纯粹是一个菊石问题。详情见答案。

【问题讨论】:

【参考方案1】:

这里的问题是菊石。

Scala REPL 有一个粘贴模式,允许您在评估之前粘贴多行:

:paste
sealed trait X
class Implementation extends X // impossible without doing it at once
// Ctrl+D

Ammonite 没有这种粘贴模式,但它 allows you to perform multi-line 复制粘贴...但将它们全部包装在 中,ammonite 会解开。所以你的代码:

 (x: Int) =>
  x
  val y = x
  y

被编译器视为

(x: Int) =>
  x // end of function definition
val y = x // new variable calling x, which isn't defined anywhere
y // call to undefined y, because previous line failed

第一个示例有效,因为您有 val f = ,因此 ammonite 的解析器不能假定 您的所有代码 都在一个块内,因此它不会在将其传递给编译器之前将其剥离。

正如文档建议的那样,如果您不想要这种行为,您应该添加另一层大括号:

 (x: Int) =>
  x
  val y = x
  y

这不是编译器和语言规范问题,而是某些特定 REPL 实现的问题。

【讨论】:

哦,天哪... 1 小时被菊石浪费了... 感谢您帮助我。 (好吧,不应该责怪菊石。只需阅读文档...) 没问题,我想我也被这个烫伤了,如果你知道的话这很方便(不仅仅是写:paste然后用Ctrl+D关闭它)但是如果你不是'不知道这是一个令人讨厌的陷阱。

以上是关于如何解释用大括号括起来的函数值(菊石问题)的主要内容,如果未能解决你的问题,请参考以下文章

数组必须用大括号括起来的初始化程序 c++ 初始化

使用RegEx通过转义获取用大括号括起来的字符串

java 为啥数组这里要用大括号?

大括号括起来的初始值设定项列表转换错误

无法从大括号括起来的初始值设定项列表转换

Replace() 不适用于多行字符串和大括号