函数式编程(FP)是一种编程范式。渊源久远。与命令式编程、面向对象编程(OOP)合称为三大编程范式。也有专门的函数式编程语言。久远如大名鼎鼎的始祖LIST语言。近如haskell等。近年来。函数式编程有逐渐发展鼎盛的趋势。相对其余两种编程范式。它有如下特点和优势:
1.1 数据不可变。对外没有副作用;
函数式编程强调数据不可变。函数里面的数值是固定的。因此象randam这种随机数是不能放在函数里面。
1.2 纯函数;
一样的输入。通过函数可以有一样的输出。意即函数对外没有副作用。这次往函数里输入1输出10。下次还是这个结果。因此咱们可以十分放心地使用函数。不用担心它会对外造成污染和出现一些不可预料、难以测试的结果。
1.3 柯里化;
多参数的函数。可以通过柯里化转变成单参数的函数。便于组合和浏览理解。柯里化是函数式编程里一个重要的特征和功能。它能够进一步把逻辑抽象出来。举例:foo a = bar foo a这样形式的一个功能函数。柯里化后。转化成 foo = bar a。既可以易于重用又容易理解。
1.4 功能组合。不易出错;
函数化编程由于它的上述特点。在实际应用中。可以大幅减少代码量。也去除了大量烦人的大括号小括号。同时通过纯函数的组合作用。可以用简短的语令实现相当复杂的功能。可以理解为柯里化后的纯函数是一个个质量可靠的乐高积木。通过这些乐高积木为基本砖块搭建的建筑极其坚固。不易坍塌。
2. 近年来趋势;
近年来。函数式编程有逐渐发展鼎盛的趋势。如大名鼎鼎的facebook的前端js框架react以及跨端应用框架react native就是充分应用了函数式编程的范例。排名前几位的编程语言。如python、javascipt 、C++等。都可以把函数作为一等对象。实现函数式编程范式的充分条件。
二、elm语言的简要说明
1. 前端语言与javascript;
近年来。前端技术发展迅速。各种前端框架层出不穷。更进一步巩固了javascript语言在前端的的地位。如haskell、LIST等的函数式编程语言。多数用在后端。
2. javascript语言的不足及替代;
Javascript强大。是一种多范式语言。也非常适合于函数式编程。但它毕竟不是一种函数语言。而且动态类型也备受研究者鞭挞。同时。多范式语言便利。但也无形中局限研究者函数式编程思维模式。
3. 近年兴起的函数式编程
为此。聪明的大牛们创造了各种不一样的框架和语言。以弥补javascript的不足。语言如purescript、conjascript、coffescript等。框架如ramda等。成功推动了函数式编程在javascript中的开花结果。
4. elm语言是其中的王者
众多语言和框架中。elm是其中的王者。Elm语言是一种静态、纯函数式编程的语言。与其它函数式语言不同。elm是专门用于前端。与平时的前端网页研究三剑客:html、css、javascript同时上阵不同。elm能抛弃其它javascript库。单纯用elm语言来构建前端UI。实现其中的逻辑功能。而且更妙的是。如果你学会elm语言和函数式编程的精髓后。能用比javascript少50%左右的代码。构建出比react、VUE、等框架更快的模块。而且还不易出错。
5. 学会elm语言的优势
使用elm语言来写UI。能养育你的函数式编程思维。当研究者们用惯了命令式、面向对象式编程思维后。函数式编程能让你的编程技术更上一层楼。对于第一次开始学的人。函数式编程是打开了编程世界的一扇大门。门后是想象不到的风景。其中蕴涵人类智慧会令你赞叹不己。而elm。就是这扇大门。这串钥匙。下面。让咱们尝试探索一下elm世界的精妙之处。
三、Elm里的lambda函数指南
1. lambda函数定义
大部分编程语言中都会有lambdas函数。它是匿名函数的代名词。建立函数时通常需要有个定语。如“function”或“def”等。例如要在javascript中定义函数sum。一般如下:
Function sum(x) {
…功能定义
lambdas匿名函数可以把function、def这类定语去掉。直接定义函数。在elm语言中。lambdas匿名函数以“\”代替。
Elm中。匿名函数的基本语法形式是:”\”+参数+“->”+功能主体。“\”号是匿名函数的定义。匿名函数后可以加多个参数。“->”提醒后面是函数功能主体定义。
2. Elm中lambdas匿名函数实现以下功能
2.1 模式匹配
例如。实现统计列表中大于10的数字数量。代码以下:
Num:int
Num sumLarge = List.length <| List.filter(/xs>10) <| List.range 1 100
两行代码便可实现。其中第一行 Num int 提醒统计数量是一个int类型定义。List.range 1 100 是生成1至100的数字列表(elm中。函数参数间以空格隔开)。“<|”是级别最低的右关联符号。意即生成列表后把列表结果作为输入向右侧函数提交。List.filter是系统默认的梳理函数。其参数是一个lambdas匿名函数。意即遵从这个函数的功能对列表进行梳理。这个lambda匿名函数(/xs>10)的功能就非常的容易理解。把大于10的数字选出来。括号也完全可以取消。转化成 “<|”右关联函数 如<|xs>10。 当把大于10的数字filter选出来后结果也是一个列表。把列表作为输入右关联到函数List.length。就得出输出结果。梳理出的列表个数。这是个int类型的数字。与第一行定义num:int一致。
注意的是。lambda匿名函数虽然给了研究者便利。但不是什么情况下都要用。有那么一些情况下。不用lambdas更好。如要把列表里的数字简单加3映射一下:
Sum: a -> List a -> List b
Sum newList = List.map(/xs = xs + 3) xs
在上例中。会感觉newList函数定义得有那么一些拖油瓶。出现了三个xs。究其原因。是因为map映射函数后定义的lambdas匿名函数拖油瓶。其实完全可以如下所写:
Sum: a -> List a -> List b
Sum newList = List.map((+) 3) xs
原来 + 号也是一个lambda函数。简单定义 (+) 3 就把原先的 xs抽离。函数功能更加抽象。这就是纯函数的意义。
2.2 类型定义
Lambda函数还可以用作类型定义。例如。要实现一个参数交换的类型定义。显式如下:
Arg: (a,b,c) -> b -> a -> c
Flip f x y = f y x
如果用lambda匿名函数的话。可以如下:
Flip f = \x y = f y x
“\”号是lambdas匿名函数。 Flip函数用匿名函数定义。既易读又比较酷。 2.3 折叠功能
elm函数式编程中。map(映射)、fliter(过滤)、foldl、foldr(折叠)是常用的几个内置函数。map和fliter方才已经使用过了。现在尝试用foldl(左折叠)和foldr(右折叠)对列表元素进行折叠实现有趣的功能。
首先是实现最基本的sum累加函数:
Sum: List number -> number
Sum xs = List.foldl(\x acc->acc+x) 0 xs
Foldl是左向折叠。对象是xs列表。0是折叠的起始值(也称累加器)。(\x acc->acc+x)就是lambdas实现累加的匿名函数。foldl每向左折叠一个元素时。就把lambdas应用其它。象扑克牌一样。到最后就成为一叠(number)了。
下一步实现一个检查元素是否在列表里的member函数:
Member: a->List a->Bool
Member y ys = List.foldl(\x acc -> if x==y then True else acc) False ys
在上例里。最终输出是一个Bool布尔判断的结果(True or False)。False作为 foldl的初始值。如果不存在元素。就False。foldl折叠的动作就是一个lambda匿名函数(\x acc -> if x==y then True else acc)。意思是判断输入元素是否与列表映射元素相符。如果相符则初始值由False变为True。否则还是原封不动)。
好了。通过折叠函数和lambdas匿名函数。咱们顺利的制作了两个新函数:sum和member。纯净没有副作用。下来就可以利用这两个新函数。作为乐高积木的最小块。来尝试组合应用一下:
New1: List a ->Bool -> int
New1 result = sum <| member 1 [1,1,2,3,4]
得出结果是: 2
New2: list a ->Bool -> int
New2: result = sum <| member [1,2] [[1,2],[2,3],[3,4]]
得出结果是: 1