为什么80%的码农都做不了架构师?>>>   

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 = 1for(i <- 0 until n){result = result*x}result}

那么无中间变量的写法呢

def expr2(x:Int,n:Int):Int={if(n==0)1else x*expr2(x,n-1)}

;-( 肯爹呢,这是。这不就是递归么。哈哈,的确函数式编程中,中间变量只是通过递归来实现中间变量。

递归与尾递归

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

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

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

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

//递归def fib(n:Int):Int = n match{case 0 => 1case 1 => 1case _ =>fib(n-1) + fib(n-2) }
//尾递归def fib2(a:Int,b:Int,n:Int):Int = n match{case 0 => bcase _ =>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太高端,它还有很多高级的应用场景,等好好研究后,会专门介绍一下。

转载于:https://my.oschina.net/FengJ/blog/159199

Scala的函数式编程相关推荐

  1. Scala入门系列(7)-Scala之函数式编程

    基础 概念 函数式编程 函数式编程中的函数指的并不是编程语言中的函数(或方法),它指的是数学意义上的函数,即映射关系(如:y = f(x)),就是 y 和 x 的对应关系. 数学上对于函数的定义是这样 ...

  2. 3000门徒内部训练绝密视频(泄密版)第3课:Scala中函数式编程彻底精通及Spark源码阅读

    Scala中函数式编程彻底精通及Spark源码阅读 函数可以不依赖于类,函数可以作为函数的参数,函数可以作为函数的返回值 =>表明对左面的参数进行右面的加工 函数赋值给变量需要在函数名后面加空格 ...

  3. Scala之函数式编程

    目录 函数和方法的区别: 参数默认值: 函数至简原则---能省则省: 至简原则细节 匿名函数的化简: 匿名函数至简原则: 高阶函数: 高阶函数的三种用法: (1)函数可以作为值进行传递 (2)函数可以 ...

  4. scala与函数式编程——从范畴论看函数式编程

    什么是范畴? 生活中我们经常说:我们讲的不是一个范畴里的东西!意思就是说两个人所讲的事物不具有任何关联,没有相关性.其实范畴Category就是指一群事物以及这些事物之间的所有关联关系,这些事物和这些 ...

  5. 2021年大数据常用语言Scala(二十一):函数式编程 遍历 foreach

    目录 遍历  foreach 使用类型推断简化函数定义 使用下划线来简化函数定义 遍历  foreach 之前,学习过了使用for表达式来遍历集合.我们接下来将学习scala的函数式编程,使用fore ...

  6. 2021年大数据常用语言Scala(二十):函数式编程 介绍

    目录 函数式编程 介绍 函数式编程的意义在哪? 函数式编程 介绍 我们将来使用Spark/Flink的大量业务代码都会使用到函数式编程.下面的这些操作是学习的重点. 现在我们将会逐渐接触函数式编程的方 ...

  7. Scala函数式编程(三) scala集合和函数

    前情提要: scala函数式编程(二) scala基础语法介绍 scala函数式编程(二) scala基础语法介绍 前面已经稍微介绍了scala的常用语法以及面向对象的一些简要知识,这次是补充上一章的 ...

  8. Scala学习教程笔记二之函数式编程、Object对象、伴生对象、继承、Trait、

    1:Scala之函数式编程学习笔记: 1:Scala函数式编程学习:1.1:Scala定义一个简单的类,包含field以及方法,创建类的对象,并且调用其方法:class User {private v ...

  9. Scala入门系列(十):函数式编程之集合操作

    1. Scala的集合体系结构 Scala中的集合体系主要包括(结构跟Java相似): Iterable(所有集合trait的根trait) Seq(Range.ArrayBuffer.List等) ...

最新文章

  1. Eclipse jee 配置Tomcat5.5
  2. 区块链开发之搭建以太坊私有链
  3. SpringBoot 页面跳转后css和js效果都无效了
  4. 在拉取和推送都存在,冲突时,用命令行解决
  5. Angular set函数和Component属性的命名冲突问题
  6. MySql优化 (2009-08-28 系统架构师大会) 演讲ppt
  7. 值类型、引用类型和泛型的前世今生
  8. 【C语言简单说】一:第一个C语言程序
  9. python特殊函数__str__、__repr__和__len__
  10. 第三部分 03 使用HTTP GET进行调用
  11. 目前比较流行的网站开发框架
  12. 量子计算的人才、软件和硬件:解开你对量子的困惑
  13. “通过端口 1433 连接到主机 127.0.0.1 的 TCP/IP 连接失败。错误:“connect timed out。请验证连接属性,并检查 SQL Server……”解决问题
  14. Android APP程序更新报解析软件包时出现错误问题解决方法
  15. LTE语音业务 - VOLTE
  16. 洛谷—P3387 【模板】缩点
  17. TODO List—2018今日头条校招
  18. easypoi导出excel不设置样式_EasyPOI 导出excel设置边框,背景颜色,字体样式
  19. 怎么快速暂停Google账户广告系列?
  20. 看大数据平台如何打造餐饮业务一体化?

热门文章

  1. html判断ie6,jquery如何判断是否是ie?
  2. leetcode刷题:无重复字符的最长子串
  3. python 抽象类和接口
  4. 3.2 选择最可能的句子
  5. opencv-api drawContours
  6. selection.text
  7. C++语言类的详解和示例
  8. python多线程没用_Python 的多线程原来不是真的多线程啊
  9. js 按给定数组的顺序给数组排序_JavaScript中如何如何给数组以及数组对象根据value值进行排序。...
  10. VMware vSphere Replication Appliance 的内部版本号和版本 (2143840)-2020-10-27更新