文档章节

Scala的函数式编程

ForEleven
 ForEleven
发布于 2013/09/04 21:22
字数 2084
阅读 8703
收藏 19

Scala的函数式编程

昨天去一家公司面试,额,他们想招erlang的开发人员,然后我会点scala,都是函数式语言么。所以就让我过去试试了,开始介绍了一些在做的项目架构什么的。最后开始跟我聊函数式编程,好吧,果断就不行了。当时开始学Scala的时候去看了下函数式编程的概念,当时也不懂,没有啥概念。只记得函数式编程不推荐使用变量,即使需要使用变量,也用不可变的变量。在Scala中也就是val定义的变量。其他的么那会就想不起来了,其实还有lambda表达式啊,这个已经知道的也没想起来。后来又让我在板子上写Partial Function,Curry Function和UnCurry Function。知道点Curry,Partial之前真的没见过。没有一点概念,回来还是得整理一下的,既然学了Scala,还是得深入了解一下函数式编程了。

Scala作为一个多范式编程语言,支持面向对象和函数式编程。虽然Scala不强求开发者使用函数式编程,不强求变量都是不可变的(通过val定义的),但是还是鼓励使用函数式编程。现在的计算机都是多核CPU,想充分利用其多核处理,我们需要写可并行计算的代码。而函数式编程在并行操作性有着天生的优势,函数式编程没有可变变量,那么就不会有内存共享的问题,也不会产生副作用(side effect)的函数。下面介绍函数式编程有哪些特性。

闭包和高阶函数

    在面向对象编程中,我们把对象作为编程中的第一类对象,所有代码的编写都是围绕对象来编程。那么函数式编程中,我们的第一类对象就是函数,也叫做 闭包 或者 仿函数 (functor)对象。而高阶函数的意思则是用另一个函数作为参数,甚至可以返回一个函数的叫做 高阶函数
val double = (i: Int) => i * 2  
//或者:val double :(Int)=> Int = _ * 2
List(1, 2, 3, 4, 5).map(double).foreach{j => print(j + " ")}
>> 2 4 6 8 10
这里我们定义了一个double函数的变量,然后作为参数传给List的map方法,然后调用foreach方法打印出来。这里double就是一个仿函数对象,而map就是一个高阶函数。

无副作用

    函数副作用维基百科的解释是:指當調用函數時,除了返回函數值之外,還對主調用函數產生附加的影響。因为函数式编程,都是函数变量或者不可变变量,所以不出出现函数副作用。但是,我们在程序设计的时候,肯定需要记录中间变量的,那么在函数式编程中,怎么来记录中间变量呢。

这是一个通过可变变量来保存每次记录值的写法来求x的n次方:

def expr(x:Int, n:Int):Int = {
    var result = 1
    for(i <- 0 until n){
      result = result*x
    }
    result
  }
那么无中间变量的写法呢
def expr2(x:Int,n:Int):Int={
    if(n==0)
      1
    else x*expr2(x,n-1)
  }
;-( 肯爹呢,这是。这不就是递归么。哈哈,的确函数式编程中,中间变量只是通过递归来实现中间变量。

递归与尾递归

    递归在函数式编程中地位不言而喻,它不仅解决了函数的副作用问题,还可以更加清晰的来写出复杂问题的处理函数。递归在函数式编程中有着大量的运用。

    尾递归的维基百科的解释:尾调用是指一个函数里的最后一个动作是一个函数调用的情形:即这个调用的返回值直接被当前函数返回的情形。这种情形下称该调用位置为尾位置。若这个函数在尾位置调用本身(或是一个尾调用本身的其他函数等等),则称这种情况为尾递归,是递归的一种特殊情形。尾调用不一定是递归调用,但是尾递归特别有用,也比较容易实现。

    在使用普通递归的时候,我们经常会见到stackoverflow的错误。而尾递归就是来解决这个问题,尾递归的每次调用的时候,不需要保存当前状态,而是把当前的状态值直接传给下次一次调用,然后清空当前的状态。那么占用的栈空间就是常量值了,不会出现栈的溢出。

下面是斐波那契数列计算的两种递归的写法

//递归
  def fib(n:Int):Int = n match{
    case 0 => 1
    case 1 => 1
    case _ =>fib(n-1) + fib(n-2) 
  }
//尾递归
  def fib2(a:Int,b:Int,n:Int):Int = n match{
    case 0 => b
    case _ =>fib2(b,a+b,n-1)
  }

惰性计算

     惰性 求值 特别用于 函数式编程语言 中。在使用延迟求值的时候,表达式不在它被绑定到变量之后就立即求值,而是在该值被取用的时候求值 除可以得到性能的提升外,惰性计算的最重要的好处是它可以构造一个无限的数据类型。

    Scala中通过lazy关键字来定义惰性变量,惰性变量只能是不可变变量。例如下面,只有在调用惰性变量b的toString方法的时候,才会去实例化b这个变量。可以看到“Test”是先打印出来的。

class Book(name:String){
    println("new book"+name)
    override def toString() = "《"+name+"》"
}

lazy val b = new Book("Java")
println("Test")
println(b.toString)
Test
new bookJava
《Java》

引用透明性

    引用透明(Referential Transparent)的概念与函数的副作用相关,且受其影响。 如果程序中两个相同值得表达式能在该程序的任何地方互相替换,而不影响程序的动作,那么该程序就具有引用透明性。它的优点是比非引用透明的语言的语义更容易理解,不那么晦涩。纯函数式语言没有变量,所以它们都具有引用透明性。


Scala中的函数

    就像面向对象编程中,我们有反射机制来动态的改变对象。在函数式编程中,当然也可以动态的来修改函数。这里只是分别做了简单的介绍,后面有时间可以详细的介绍一下它们各自。

Partial Function

    Partial Function局部方法,可以动态的将一个函数的任意位置的参数提供默认值,获得新的函数。新函数的参数个数从而发生改变。

比如我们有个函数,将字符b复制a次然后跟c拼接。

val f = (a: Int, b: String, c: String) => b * a + c
val f2 = f(5,_:String,_:String)  // 为复制次数指定默认5次
println(f2("A","B"))  >> AAAAAB
val f3 = f(_: Int, "A", _: String) // 为被复制的值指定默认为A
println(f3(5, "B"))

Curry

    比如有一个函数 f(a,b),通过Curry化以后的函数可以变成f1(a)(b),然后我们通过Partial函数f3= f1(10) _ 。这时候f3(2) == f(10,2) 

//curry化
val curry = new Function3[Int,String,String,String](){
    def apply(a: Int, b: String, c: String) = f(a,b,c)
  }
或者:val f6 = f.curried(10)(_:String)(_:String)
// 设定遍历次数默认值
  val f4 = curry.curried(10)(_:String)(_:String)
   println(f4("A","B"))

Implicit 

    隐式函数(Implicit Function)的原理不太明白,它的运用场景就是可以动态给一个类添加一个方法,在Scala中甚至是JDK中定义的final类。下面,我们为java的String添加一个方法。

object Simple {
  implicit def wrapper(s:java.lang.String) =new {def wrap= "--" + s +"--"}
}

val s :java.lang.String = "Hello" 
println(s.wrap)  >>> --Hello--

我们只需要在静态类中定义一个隐式方法,该方法的参数就是被隐式添加方法的类。当scala的编译器 编译 s.wrap 时,因为 String 类中没有 wrap方法,编译器会寻找代码中方法签名相同的 wrapper(s :String)。

Implicit Function太高端,它还有很多高级的应用场景,等好好研究后,会专门介绍一下。

© 著作权归作者所有

共有 人打赏支持
ForEleven
粉丝 208
博文 32
码字总数 28047
作品 1
架构师
Scala 是个有趣的语言

[英文出处]:Why Scala Is Interesting [中文翻译]:外刊IT评论 经常读我的博客的人应该知道,我最喜欢的编程语言是Haskell。我喜欢函数式编程,Haskell是一个能把函数式编程推向极致的语言。...

鉴客
2010/08/18
1K
1
[转]Scala是个有趣的语言

经常读我的博客的人应该知道,我最喜欢的编程语言是Haskell。我喜欢函数式编程,Haskell是一个能把函数式编程推向极致的语言。虽然如此,我仍然时刻关注着其它新兴的和即将产生的编程语言,特...

mj4738
2011/11/01
0
0
Scala编程语言视频教程|Scala视频教程

Scala编程语言视频教程 分享网盘下载——https://pan.baidu.com/s/1kUFL6Ub 密码: m7k4 Scala是一种多范式的编程语言,其设计的初衷是要集成面向对象编程和函数式编程的各种特性。Scala运行于...

nitycka
2017/11/01
0
0
编程语言 Scala 2.12.0-M1 发布

Scala 2.12.0-M1 发布,Scala 2.12 系列的目标是 Java 8。 下载:scala-lang.org Maven Central Scala 2.12 改进计划: Java 8 style closures. Lambda syntax for SAM types New backend a......

oschina
2015/05/10
2.6K
16
编程语言--Scala

Scala是一门现代的多范式编程语言,志在以简练、优雅及类型安全的方式来表达常用编程模式。它平滑地集成了面向对象和函数语言的特性。 Scala是面向对象的:Scala是一个纯面向对象语言,在某种...

匿名
2008/11/11
71.1K
12

没有更多内容

加载失败,请刷新页面

加载更多

下一页

深夜胡思乱想

魔兽世界 最近魔兽世界出了新版本, 周末两天升到了满级,比之前的版本体验好很多,做任务不用抢怪了,不用组队打怪也是共享拾取的。技能简化了很多,哪个亮按哪个。 运维 服务器 产品 之间的...

Firxiao
16分钟前
0
0
MySQL 8 在 Windows 下安装及使用

MySQL 8 带来了全新的体验,比如支持 NoSQL、JSON 等,拥有比 MySQL 5.7 两倍以上的性能提升。本文讲解如何在 Windows 下安装 MySQL 8,以及基本的 MySQL 用法。 下载 下载地址 https://dev....

waylau
50分钟前
0
0
微信第三方平台 access_token is invalid or not latest

微信第三方开发平台code换session_key说的特别容易,但是我一使用就带来无穷无尽的烦恼,搞了一整天也无济于事. 现在记录一下解决问题的过程,方便后来人参考. 我遇到的这个问题搜索了整个网络也...

自由的开源
今天
0
0
openJDK之sun.misc.Unsafe类CAS底层实现

注:这篇文章参考了https://www.cnblogs.com/snowater/p/8303698.html 1.sun.misc.Unsafe中CAS方法 在sun.misc.Unsafe中CAS方法如下: compareAndSwapObject(java.lang.Object arg0, long a......

汉斯-冯-拉特
今天
2
0
设计模式之五 责任链模式(Chain of Responsibility)

一. 场景 相信我们都有过这样的经历; 我们去职能部门办理一个事情,先去了A部门,到了地方被告知这件事情由B部门处理; 当我们到了B部门的时候,又被告知这件事情已经移交给了C部门处理; ...

JackieRiver
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部