• 函数式编程(Funtional Programming,简称FP)是一种编程范式,也就是如何编写程序的方法论
  1. 主要思想:把计算过程尽量分解成一系列可复用函数的调用
  2. 主要特征:函数是“第一等公民”:

    函数与其他数据类型一样的地位,可以赋值给其他变量,也可以作为函数参数、函数返回值
  • 函数式编程最早出现在LISP语言,绝大大部分的代码编程语言也对函数式编程做了不同程度的支持,比如:Haskell、JavaScript、Python、Swift、Kotlin、Scala等
  • 函数时编程中的几个常用的概念
  1. Higher-Order Function、Function Currying
  2. Functor、Applicatie Functor、Monad

FP实践 - 传统写法

  • 常规写法
// 假设要实现以下功能:[(num + 3) * 5 - 1] % 10 / 2
let num = 1
func add(_ v1: Int, _ v2: Int) -> Int { v1 + v2 }
func sub(_ v1: Int, _ v2: Int) -> Int { v1 - v2 }
func multiple(_ v1: Int, _ v2: Int) -> Int { v1 * v2 }
func divide(_ v1: Int, _ v2: Int) -> Int { v1 / v2 }
func mod(_ v1: Int, _ v2: Int) -> Int { v1 % v2 }
let result = divide(mod(sub(multiple(add(num, 3), 5), 1), 10), 2)
print(result) // 4

FP实践 - 函数式写法

  • 柯里化
func add(_ v: Int) -> (Int) -> Int { { $0 + v } }
func sub(_ v: Int) -> (Int) -> Int { { $0 - v } }
func multiple(_ v: Int) -> (Int) -> Int { { $0 * v } }
func divide(_ v: Int) -> (Int) -> Int { { $0 / v } }
func mod(_ v: Int) -> (Int) -> Int { { $0 % v } }
  • 函数合成
func composite(_ f1: @escaping (Int) -> Int,
_ f2: @escaping (Int) -> Int) -> (Int) -> Int {
return { f2(f1($0)) }
}
let fn = composite(add(3), multiple(5))
print(fn(num)) // 20
  • 函数合成 - 利用符号
infix operator >>>: AdditoinPrecedence
func >>>(_ f1: @escaping (Int) -> Int,
_ f2: @escaping (Int) -> Int) -> (Int) -> Int { return { f2(f1($0)) } }
let fn = add(3) >>> multiple(5)
print(fn(num)) // 20 函数合成 - 利用符号 - 泛型
infix operator >>>: AdditoinPrecedence
func >>> <A, B, C>(_ f1: @escaping (A) -> B,
_ f2: @escaping (B) -> C) -> (A) -> C { return { f2(f1($0)) } }
let fn = add(3) >>> multiple(5)
print(fn(num)) // 20
let fn = add(3) >>> multiple(5) >>> sub(1) >>> mod(10) >>> divide(2)
print(fn(num)) // 4

高阶函数(Higher-Order Function)

  • 高阶函数是至少满足下列一个条件的函数:
  1. 接受一个或多个函数作为输入(map、filter、reduce等)
  2. 返回一个函数
  • FP中到处都是高阶函数

柯里化(Currying)

  • 将一个接受多参数的函数变换为一系列只接受单个参数的函数
func add1(_ v1: Int, _ v2: Int) -> Int { v1 + v2 }
add1(10, 20)
func add1(_ v: Int) -> (Int) -> Int { { $0 + v } }
add1(10)(20)
  • Array、Optional的map方法接受的参数就是一个柯里化函数
  • 三个参数柯里化
func add2(_ v1: Int, _ v2: Int, v3: Int) -> Int { v1 + v2 + v3 }
func add2(_ v3: Int) -> (Int) -> (Int) -> Int {
// v2 == 20
return { v2 in
// v1 == 10
return { v1 in
return v1 + v2 + v3
}
}
}
add2(10, 20, 30)
add2(30)(20)(10)
  • 两个参数柯里化 - 泛型
func currying<A, B, C>(_ fn: @escaping (A, B) -> C) -> (B) -> (A) -> C {
return { b in
return { a in
return fn(a, b)
}
}
}
currying(add1(20)(10))
  • 两个参数柯里化- 利用符号 - 泛型
prefix func ~<A, B, C>(_ fn: @escaping (A, B) -> C)
-> (B) -> (A) -> C {
{ b in { a in fn(a, b) } }
}
print((~sub(20)(10)) // -10
// 合成函数-> 泛型柯里化
let fn = (~add)(3) >>> (~multiple)(5) >>> (~sub)(1) >>> (~mod)(10) >>> (~divide)(2)
print(fn(1)) // 4
  • 三个参数柯里化 - 利用符号 - 泛型
prefix func ~<A, B, C, D>(_ fn: @escaping (A, B, C) -> D)
-> (C) -> (B) -> (A) -> D {
{ c in { b in { a in fn(a, b, c) } } }
}
print((~add2)(30)(20)(10)) // 60

函子(Functor)

  • 像Array、Optional这样支持map运算的类型,成为函子(Functor)
  • 怎么样的Type才能称之为函子呢?
func map<T>(_ fn: (Inner) -> T) -> Type<T>
  • 数组和可选项是符合函子规定的公式:
func map<T>(_ fn: (Element) -> T) -> Array<T>   // [T]
func map<T>(_ fn: (Wrapped) -> T) -> Opional<T> // T?

适用函子(Applicative Functor)

  • 对任意一个函子F,如果能支持一下运算,该函子就是一个适用函子
func pure<A>(_ value: A) -> F<A>
func <*><A, B>(fn: F<(A) -> B>, value: F<A>) -> F<B>
  • Optional可以成为适用函子
func pure<A>(_ value: A) -> A? { value }
infix operator <*>: AdditionPrecedence
func <*><A, B>(fn: ((A) -> B)?, value: A?) -> B? {
guard let f = fn, let v = value else { return nil }
return f(v)
}
var value: Int? = 10
var fn: ((Int) -> Int)? = { $0 * 2 }
// Optional
print(fn <*> value as Any)

![在这里插入图片描述](https://img-blog.csdnimg.cn/20190923152402722.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3Nvbmd6aHVvMTk5MQ==,size_16,color_FFFFFF,t_70 =240x300)

  • Array可以成为适用函子
func pure<A>(_ value: A) -> [A] { [value] }
func <*><A, B>(fn: [(A) -> B], value: [A]) -> [B] {
var arr: [B] = []
if fn.count == value.count {
for i in fn.startIndex..<fn.endIndex {
arr.append(fn[i](value[i]))
}
}
return arr
}
// [10]
print(pure(10))
var arr = [{ $0 * 2 }, { $0 + 10 }, { $0 - 5 }] <*> [1, 2, 3]
// [2, 12, -2]
print(arr)

单子(Monad)

  • 对于任意一个类型F,如果能支持一下运算,那么就可以成为是一个单子(Monad)
func pure<A>(_ value: A) -> F<A>
func flatMap<A, B>(_ value: F<A>, _ fn: (A) -> F<B>) -> F<B>
  • 很显然,Array、Optional都是单子

编程范式 --- 函数式编程(Funtional Programming,简称FP)的更多相关文章

  1. Scala编程入门---函数式编程之集合操作

    集合的函数式编程: 实战常用: //map案例实战:为List中的每个元素都添加一个前缀. List("leo","Jen","peter" ...

  2. Scala编程入门---函数式编程

    高阶函数 Scala中,由于函数时一等公民,因此可以直接将某个函数传入其他函数,作为参数.这个功能是极其强大的,也是Java这种面向对象的编程语言所不具备的. 接收其他函数作为函数参数的函数,也被称作 ...

  3. Scala函数与函数式编程

    函数是scala的重要组成部分, 本文将探讨scala中函数的应用. scala作为支持函数式编程的语言, scala可以将函数作为对象即所谓"函数是一等公民". 函数定义 sca ...

  4. swift之函数式编程

    函数式编程初探 最近初学swift,和OC比,发现语言更现代,也有了更多的特性.如何写好swift代码,也许,熟练使用新特性写出更优秀的代码,就是答案.今天先从大的方向谈谈swift中的编程范式-函数 ...

  5. Python 进阶(一)函数式编程

    来自慕课网: 简介: 函数:function ,在入门课程已学 函数式:functional,一种编程范式 函数式编程是一种抽象计算的编程模式,函数≠函数式,好比:计算≠计算机

  6. javascript 函数式编程

    编程范式 编程范式是一个由思考问题以及实现问题愿景的工具组成的框架.很多现代语言都是聚范式(或者说多重范式): 他们支持很多不同的编程范式,比如面向对象,元程序设计,泛函,面向过程,等等. 函数式编程 ...

  7. Python进阶之函数式编程(把函数作为参数)

    什么是函数式编程? 什么是函数式编程? 函数:function 函数式:functional,一种编程范式 函数式编程是一种抽象计算的编程模式 函数≠函数式,比如:计算≠计算机 在计算机当中,计算机硬 ...

  8. 编程范式:命令式编程(Imperative)、声明式编程(Declarative)和函数式编程(Functional)

    主要的编程范式有三种:命令式编程,声明式编程和函数式编程. 命令式编程: 命令式编程的主要思想是关注计算机执行的步骤,即一步一步告诉计算机先做什么再做什么. 比如:如果你想在一个数字集合 collec ...

  9. Lambda01 编程范式、lambda表达式与匿名内部类、函数式接口、lambda表达式的写法

    1 编程范式 主要的编程范式有三种:命令式编程,声明式编程和函数式编程. 1.1 命令式编程 关注计算机执行的步骤,就是告诉计算机先做什么后做什么 1.2 声明式编程 表达程序的执行逻辑,就是告诉计算 ...

随机推荐

  1. React项目升级遇到的问题复盘(2019-09-02)

    老铁们,发没发现我换了个贼帅的头像,高端大气上档次,非洲大地我最凶!可把我自己牛逼坏了. 不扯啦不扯啦,抓紧进入今天的正题,从今天开始我会每天写一下每天工作的出现的问题,主要对这些问题出现的原因,以及 ...

  2. xcode删除一个项目

    退出xcode. 在Finder中删除项目文件夹.

  3. URAL-1627-Join 生成树计数

    传送门:https://vjudge.net/problem/URAL-1627 题意: 给定一个n*m的图,问图中“.”的点生成的最小生成树有多少个. 思路: 生成树的计数,需要用Kirchhoff ...

  4. ACM-ICPC 2018 沈阳赛区(网络赛)

    D.Made In Heaven One day in the jail, F·F invites Jolyne Kujo (JOJO in brief) to play tennis with he ...

  5. HDU 5324 Boring Class CDQ分治

    题目传送门 题目要求一个3维偏序点的最长子序列,并且字典序最小. 题解: 这种题目出现的次数特别多了.如果不需要保证字典序的话直接cdq就好了. 这里需要维护字典序的话,我们从后往前配对就好了,因为越 ...

  6. poj 1456 Supermarket(贪心+优先队列)

    题目链接:http://poj.org/problem?id=1456 题意:有N件商品,分别给出商品的价值和销售的最后期限,只要在最后日期之前销售处,就能得到相应的利润,并且销售该商品需要1天时间. ...

  7. 第11讲-Java泛型和文件操作

    1.知识点 1.1.课程回顾 1.2.本章重点 1.2.1.泛型 1.2.2.文件操作 2.具体内容 2.1.Java泛型 2.1.1.为什么需要泛型 我们发现在List中,底层是Object[ ]数 ...

  8. JS-DOM ~ 02. 隐藏二维码、锁定、获取输入框焦点、for循环为文本赋值、筛选条件、全选和反选、属性的方法操作、节点的层次结构、nodeType

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. 一起来读Netty In Action之传输(三)

    当我们的应用程序需要接受比预期多很多的并发连接的时候,我们需要从阻塞传输切换到非阻塞传输上去,如果是我们的网络编程是基于jdk提供的API进行开发地的话,这种传输模式的切换几乎要我们重构整个网络传输相 ...

  10. 渗透之路基础 -- 服务端请求伪造SSRF

    简介:SSRF 服务器端请求伪造,有的大型网站在web应用上提供了从其他服务器获取数据的功能.使用户指定的URL web应用获取图片,下载文件,读取文件内容.通常用于控制web进而探测内网服务以及攻击 ...