【Scala十六】Scala核心十:柯里化函数

编程技术  /  houtizong 发布于 3年前   191

本篇文章重点说明什么是函数柯里化,这个语法现象的背后动机是什么,有什么样的应用场景,以及与部分应用函数(Partial Applied Function)之间的联系

 

1. 什么是柯里化函数

A way to write functions with multiple parameter lists. For instancedef f(x: Int)(y: Int) is a curried function with two parameterlists. A curried function is applied by passing several argumentslists, as in: f(3)(4). However, it is also possible to write a partialapplication of a curried function, such as f(3).

也就是说,有多个参数列表 的函数就是柯里化函数,所谓的参数列表就是使用小括号括起来的函数参数列表

 

2. 柯里化函数的设计动机

每个语言现象都有它的动机,即为解决什么问题而引入了柯里化函数这个语言现象

 

以如下的柯里化函数sum为例,Scala在执行sum(1)(2)的时候,实际上是执行了两次函数调用,首先执行sum(1)_返回一个函数,这个函数是一个部分应用函数,为这个部分应用函数提供参数2后,得到结果

scala> def sum(x:Int)(y:Int)=x+ysum: (x: Int)(y: Int)Int               scala> val second = sum(1)_second: Int => Int = <function1>scala> second(2)res1: Int = 3scala>

 

sum(1)_这个偏函数表示的是第二个函数

 

柯里化函数执行时,分解为两个函数执行,步骤与下面的方法调用过程类似

 

scala> def first(x:Int) = (y:Int)=>x+yfirst: (x: Int)Int => Intscala> val second = first(1)second: Int => Int = <function1>scala> second(2)res4: Int = 3

  

柯里化实现Java7的try-with-resources控制结构

 

package spark.examples.scalaimport java.io.FileInputStreamobject CurryTest {  def withIOStream(stream: java.io.InputStream)(func: java.io.InputStream => Unit) {    try {      func(stream)    } finally {      stream.close()    }  }  def read(stream: java.io.InputStream) = {    println(stream.available())  }  def main(args: Array[String]) {    withIOStream(new FileInputStream("d:/people.txt")) {      println("Hello,Start to read")      read    }  }

 

柯里化函数withIOStream中的func参数也可以和stream放在一起,使得withIOStream成为一个普通的函数,但是使用者在用的时候,就无法实现像CurryTest中使用的那样体现Java7的try-with-resource风格,具有明显的代码控制结构的意味在里面。

 

 

curry化最大的意义在于把多个参数的function等价转化成多个单参数function的级联,这样所有的函数就都统一了,方便做lambda演算。 在scala里,curry化对类型推演也有帮助,scala的类型推演是局部的,在同一个参数列表中后面的参数不能借助前面的参数类型进行推演,curry化以后,放在两个参数列表里,后面一个参数列表里的参数可以借助前面一个参数列表里的参数类型进行推演。这就是为什么 foldLeft这种函数的定义都是curry的形式

 

 

 

object FoldLeftRightTest { def main(args: Array[String]) {    val list = List(1, 3, 5)    //折叠操作是一个递归的过程,将上一次的计算结果代入到函数中    //作为结果的参数在foldLeft是第一个参数,在foldRight是第二个参数    //foldLeft表示从左向右折叠,从最左边的元素向最右边的元素折叠    val c = list.foldLeft("String:")((x: String, y: Int) => x + y) //String:135    println(c)    val cc = list.foldLeft("String:")((x: String, y: Int) => y + x) //531String:    println(cc)    /* /:是foldLeft的符号表示*/    val ccc = list./:("String:")((x: String, y: Int) => x + y) //String:135    println(ccc)    val d = list.foldLeft(100)((x: Int, y: Int) => x + y) //109    println(d)    //foldRight表示从右向左折叠,从最右边的元素向最左边的元素折叠    val e = list.foldRight("String:")((y: Int, x: String) => x + y) //String:531    println(e)    val f = list.foldRight("String:")((y: Int, x: String) => y + x) //135String:    println(f)    //:\是foldRight的符号表示    val g = list.:\("String:")((y: Int, x: String) => y + x) //135String:    println(g)  }}
 

 关于柯里化函数类型推演的例子:

 

class A {  class B}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]) {  }}

 

 

 

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!

留言需要登陆哦

技术博客集 - 网站简介:
前后端技术:
后端基于Hyperf2.1框架开发,前端使用Bootstrap可视化布局系统生成

网站主要作用:
1.编程技术分享及讨论交流,内置聊天系统;
2.测试交流框架问题,比如:Hyperf、Laravel、TP、beego;
3.本站数据是基于大数据采集等爬虫技术为基础助力分享知识,如有侵权请发邮件到站长邮箱,站长会尽快处理;
4.站长邮箱:[email protected];

      订阅博客周刊 去订阅

文章归档

文章标签

友情链接

Auther ·HouTiZong
侯体宗的博客
© 2020 zongscan.com
版权所有ICP证 : 粤ICP备20027696号
PHP交流群 也可以扫右边的二维码
侯体宗的博客