函数是函数式编程的基本,在scala中你可以这样定义一个函数
val fun: Int => Int = i => i * i val fun2 = (i: Int) => i * i都达到了power(x,2)的想要结果
如果在repl中会显示,
val fun: Int => Int = i => i * i
scala> val fun: Int => Int = i => i * i
fun: Int => Int = <function1>
那么 <function1>是什么呢,其实是
trait Function1
{
实际上fun是Functon1的一个实例,在scala中,为我们定义了Funtion0~Function22 23个函数接口。override def toString() = "<function1>"}
足够我们用了。
每次调用fun实际上是调用Function1.apply而已。
下面定义一个方法,
def mul(x: Int, y: Int) = x * y引用baike
在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。这个技术由 Christopher Strachey 以逻辑学家 Haskell Curry 命名的,尽管它是 Moses Schnfinkel 和 Gottlob Frege 发明的。
尝试把mul 定义成柯里化的形式
scala > def mulCurry(x:Int)(y:Int)=x*y
mulCurry: (x: Int)(y: Int)Int
scala> mul(2,3)
res3: Int = 6
scala> mulCurry(2)(3)
res5: Int = 6
柯里化和普通方法执行结果是一致的
mulCurry(2)(3)实际上是依次调用两个普通函数(非柯里化函数),第一次调用使用一个参数 x,返回一个函数类型的值,第二次使用参数y调用这个函数类型的值。
实际上Curry也可表示为
def mulCurry(x: Int) = (y: Int) => x * y
scala> mulCurry(2)
res1: Int => Int = <function1>
返回的是一个函数类型的值 (val)输入第二个参数时再调用第一次生成的函数
scala> res1(2)
res2: Int = 4
柯里化常用在含隐式函数调用的地方,隐式函数下回分解
- curry化最大的意义在于把多个参数的function等价转化成多个单参数function的级联,这样所有的函数就都统一了,方便做lambda演算。 在scala里,curry化对类型推演也有帮助,scala的类型推演是局部的,在同一个参数列表中后面的参数不能借助前面的参数类型进行推演,curry化以后,放在两个参数列表里,后面一个参数列表里的参数可以借助前面一个参数列表里的参数类型进行推演。这就是为什么 foldLeft这种函数的定义都是curry的形式
object CurryTest { //定义为柯里化函数时没有问题的,b的类型可以由a参与得出 def method(a: A)(b: a.B) { } //参数列表的第二个参数,a没有定义,不能参与b的类型推断 def method2(a: A, b: a.B /*a is not defined in a.B*/) { } def main(args: Array[String]) { } }
下面一个例子摘自programming scala
import scala.util.control.NonFatal // DeanW (Dec. 21, 2015): Refined the implementation and the usage // example below to more clearly indicate the handling of the returned // object of type T. object manage {
def apply[R <: { def close():Unit }, T](resource: => R)(f: R => T): T = { var res: Option[R] = None try { res = Some(resource) // Only reference "resource" once!! f(res.get) // Return the T instance } catch { case NonFatal(ex) => println(s"manage.apply(): Non fatal exception! $ex") throw ex } finally { if (res != None) { println(s"Closing resource...") res.get.close } } } } object TryCatchARM { /** Usage: scala rounding.TryCatch filename1 filename2 ... */ def main(args: Array[String]) = { val sizes = args map (arg => returnFileLength(arg)) println("Returned sizes: " + (sizes.mkString(", "))) } import scala.io.Source def returnFileLength(fileName: String): Int = { println() // Add a blank line for legibility manage(Source.fromFile(fileName)) { source => val size = source.getLines.size println(s"file $fileName has $size lines") if (size > 200) throw new RuntimeException(s"Big file: $fileName!") size } } }R可以认为是CloseAble的子类,利用柯里化技术,实现了java7的try with release编程。这是一个综合性例子,包含泛型,option,柯里化,call by name。