[转帖]Scala的函数式编程特性_Android, Python及开发编程讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  Android, Python及开发编程讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 3042 | 回复: 0   主题: [转帖]Scala的函数式编程特性        下一篇 
wei.wang
注册用户
等级:少校
经验:1001
发帖:87
精华:0
注册:2013-8-29
状态:离线
发送短消息息给wei.wang 加好友    发送短消息息给wei.wang 发消息
发表于: IP:您无权察看 2013-9-9 10:27:19 | [全部帖] [楼主帖] 楼主

闭包和高阶函数


       在面向对象编程中,我们把对象作为编程中的第一类对象,所有代码的编写都是围绕对象来编程。那么函数式编程中,我们的第一类对象就是函数,也叫做 
闭包

或者 

仿函数


(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太高端,它还有很多高级的应用场景,等好好研究后,会专门介绍一下。




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论