斯卡拉的咖喱和关闭

时间:2017-04-03 15:26:42

标签: scala closures currying

我正在准备关于Scala和函数式编程的演示文稿,我不确定两个概念。

我在演示期间使用了之前介绍的功能:

def safe_division(x: Int, y: Int) : Option[Double] = {
  if(y != 0)
    Some(x / y.toDouble)
  else
    None
}

我创建了一个咖喱版(如果我错了请纠正我!):

val curried_safe_division: (Int) => (Int) => Option[Double] = {
  (x) => 
    (y) =>     
      if(y != 0)
        Some(x / y.toDouble)
      else
        None
}

所以我不确定的第一部分是“curried_safe_division被称为咖喱?”

然后我介绍一些代码来说明currying函数如何让程序员有效地重用函数:

val divideSix = curried_safe_division(6)
divideSix(3)
// prints: Some(2.0)
divideSix(6)
// prints: Some(1.0)

我是否正确地说divideSix是封闭的? curried_safe_division也不是关闭吗? 我正在使用这个定义:

  

https://softwareengineering.stackexchange.com/a/40708   一个可以存储为变量的函数(称为“第一类函数”),它具有访问其创建范围本地的其他变量的特殊能力。

我在线阅读多个资源,维基百科页面和此stackoverflow问题:What is a 'Closure'?但它仍然不是 超级 清除

2 个答案:

答案 0 :(得分:4)

curried_safe_division是一个函数。这与safe_division不同,后者是一种方法。

此外,curried_safe_division curried功能。当您使用safe_division并将其转换为函数时,您通常会得到(Int, Int) => Option[Double]。通过将其更改为Int => Int => Option[Double],您 curried 该功能。

函数divideSix不是闭包。它是一个简单的函数,它接受一个整数并返回一个整数。然而,什么是闭包是curried_safe_division中的内部函数:

val curried_safe_division: (Int) => (Int) => Option[Double] =
    (x) => 
    // function below is a closure   
      (y) =>     
        if(y != 0)
          Some(x / y.toDouble)
        else
          None
    // end of closure
  }

您可以清楚地看到它取决于x,但不会将其作为自己的参数;相反,它使用了外部范围的x。它"关闭x"。当您说val divideSix = curried_safe_division(6)时,您正在接受该闭包,为其提供六个作为参数x的值,并将其分配给divideSix。但是divideSix本身并不是一个闭包。它并不关闭任何东西。它只需要一个整数参数并将其除以6。

我已经看到有些人倾向于将结果函数值(在我们的例子中为divideSix)引用为" closure"因为它是部分应用某个函数(在我们的例子中为curried_safe_division)而产生的函数,并且导致了一个函数(在我们的例子中的注释之间标记),这是一个实际的闭包。我很好。只要您了解机制,就可以很容易地找到术语。

答案 1 :(得分:1)

Currying实际上比你的例子简单得多。您不需要同时引入方法/功能区分。

// a curried safe_division method
def safe_division(x: Int)(y: Int) : Option[Double] =
  if (y != 0) Some(x / y.toDouble)
  else        None

您可以在此处介绍eta expansionsafe_division(2)_,它会创建Int => Option[Double]类型的函数。