是否可以在 Scala 中创建一个不允许使用闭包的函数?

Is it possible in Scala to make a function that disallows the use of closures?

提问人:Jared DuPont 提问时间:9/21/2019 最后编辑:Jared DuPont 更新时间:9/21/2019 访问量:50

问:

假设我有一些这样的功能:

def doSomeCode(code: => Unit): Unit = {
  println("Doing some code!")
  code
}  

它接受一个函数,打印出“正在做一些代码!”,然后调用传递的函数。例如,如果我们这样称呼它:

doSomeCode {
  println("Some code done!")
}

它会打印出“正在做一些代码!”,然后是“一些代码完成了!”。

但我想禁止在该代码块中使用外部变量,例如:

def otherFunction(): Unit = {
  val number = 10

  doSomeCode{
    println("The number is " + number)
  }
}

这将打印出“正在做一些代码!”,然后是“数字是 10”。但我希望它抛出一个错误,因为我不想在 doSomeCode 的范围内。这在 Scala 中可能实现吗?
需要明确的是,我不是在问这是否是一个好主意,我只是想知道它是否可行。
number

编辑:
我想要这个的原因是因为我试图制作一个功能完美的语法,我想要一个没有副作用的块。理想情况下,语法如下所示:

val a = 1
val b = 2
val c = 3
val d = 4

val sum = use(a, c, d){
  val total = a + c + d
  total
}  

这样,作为程序员,我就知道唯一使用的变量是 、 ,这是唯一的输出。尝试使用其他任何内容(例如 )将导致错误。目前,无法一目了然地知道一个块使用了哪些变量。我可以通过制作和使用这样的函数来实现这一点:acdsumb

def example(): Unit = {
  val a = 1
  val b = 2
  val c = 3
  val d = 4

  val sum = sum(a, c, d)
}

def sum(a: Int, b: Int, c: Int): Int = {
  val total = a + b + c
  total
}  

它的行为与我想要的完全一样,但我希望它与其他代码内联,而不是作为外部函数。

Scala 范围 闭包

评论

3赞 Luis Miguel Mejía Suárez 9/21/2019
我怀疑这是否可能。使用某些宏可能是可行的,但这并不容易。你想要这个有什么理由吗?听起来像是一个 XY 问题
0赞 Jared DuPont 9/21/2019
编辑了带有解释的帖子。基本上,我只想要一个可能副作用为零的示波器块
2赞 Luis Miguel Mejía Suárez 9/21/2019
这是一项崇高的事业,但它已经失败了。打印是副作用,读时钟是副作用。你可以做很多事情,而无需访问任何外部的东西。最后,所有变量都在范围内,并且由于它们没有突变,因此读取它们不会产生副作用。- 无论如何,你有没有看过,基本上,如果你在 IO 中有一个值,它只能在通话中使用。这是我所知道的最接近的。cats.effect.IOflatMap
0赞 Jared DuPont 9/21/2019
对不起,我应该更具体一点。我对传入的变量、标准 IO、普通语言调用的副作用没问题。我特别想要的是让块中的代码表现得像在其他地方定义的函数中一样,但内联。查看最近的编辑
1赞 jbx 9/21/2019
为什么不简单地将代码封装在采用参数的函数中呢?这样,您就可以一目了然地知道哪些是闭包的自由变量。

答:

1赞 Levi Ramsey 9/21/2019 #1
scala> def mkClosure(i: Int) = { s: String => s"$i - $s" }
mkClosure: (i: Int)String => String

scala> mkClosure(5)
res0: String => String = <function1>

由于函数是否依赖于非参数的值未在类型系统中编码,因此在 Scala 中,此类函数和纯函数之间没有编译器可强制执行的区别。使用宏不太可能实现:编译器插件可能是您最好的选择,特别是如果您想允许在块内使用某些值(例如)。println