当前位置: 首页 > news >正文

【学习笔记】函数式编程

一、相关概念

函数式编程(Functional Programming,FP):

  • 把现实世界的事物和事物之间的联系抽象到程序世界(对运算过程进行抽象)。
  • 是一种编程范式(编程风格),同纬度有面向对象编程、面向过程编程。

函数式编程的思维方式:

  • 函数式编程中的函数指的不是程序中的函数(方法),而是数学中的函数即映射关系(x->f(映射、联系)->y,y=f(x))。
  • 相同的输入始终要得到相同的输出(纯函数)

函数是一等公民(First-class Function)

  • 函数可以存储在变量中(函数表达式)
  • 函数作为参数
  • 函数作为返回值

高阶函数(Higher-order function)

  • 高阶函数:函数作为参数 或 函数作为返回值
  • 常用的高阶函数:forEach、map、filter、every、some、find/findIndex、reduce、sort

纯函数:相同的输入永远的到相同的输出,而且没有任何可观察的副作用

  • 好处:
    • 可缓存
    • 可测试
    • 并行处理
  • 副作用:让一个函数变得不纯——依赖于外部的状态,无法保证相同输出
    • 配置文件
    • 数据库
    • 全局变量
    • 获取用户的输入

柯里化(Currying):解决硬编码问题

  • 柯里化可以让我们给一个函数传递较少的参数得到一个已经记住了某些固定参数的新函数
  • 柯里化内部使用了闭包来对函数参数进行缓存
  • 让函数更灵活,颗粒度更小
  • 可以把多元函数转换成一元函数,可以组合使用函数产生强大功能

函数组合(compose):如果一个函数要经过多个函数处理才能得到最终值,这个时候可以把中间过程合并成一个函数

  • 类似数据管道
  • 函数组合默认从右到左执行
  • 函数组合要满足结合律(associativity)
    • 假如compose(f,g,h),既可以把f和g组合,也可以把g和h组合,结果都是一样的

函数组合的作用:可以避免洋葱代码,把细粒度的函数重新组合成一个新的函数。

函数式编程相关库:lodash、underscore、ramda

lodash中的组合函数:

  • flow 从左到右运行
  • flowRight 从右到左运行

Lodash/fp

  • lodash 的fp 模块提供了实用的对函数式编程友好的方法
  • 提供了不可变 *auto-curried iteratee-first data-last** 的方法

Pointfree: 函数风格。

  • 不需要指明处理的数据
  • 只需要合成运算过程
  • 需要定义一些辅助的基本运算函数

Functor (函子):是一个特殊的容器,通过一个普通的对象来实现,该对象具有map方法,map方法可以运行一个函数对值进行处理(变形关系)

  • 容器:包含值和值的变形关系(这个变形关系就是函数)
  • 函子:
    • MayBe 函子:可以对外部的空值情况做处理(控制副作用在允许的范围)
    • Either 函子:二选一,两者中的任意一个。类似于if...else;异常会让函数遍的不纯,Either 函子可以用来做异常处理
    • IO 函子:IO 函子中的_value 是一个函数,这里是把函数作为值来处理;可以把不纯的动作存储到_value 中,延迟执行这个不纯的操作(惰性执行),包装当前的操作纯;把不纯的操作交给调用者来处理
    • Task 异步执行:使用folktale中的compose、curry
    • Pointed 函子:Pointed函子是实现了of静态方法的函子;of方法为了避免new来创建对象,更深层的含义是of方法用来把值放到上下文Context
    • Monad 函子:Monad 函子是可以变扁的Pointed 函子,IO(O(x));一个函子如果具有 join 和 of 两个方法并遵守一些定律就是一个Monad

二、相关代码

// 闭包——函数作为返回值
function makeFn() {
  let msg = 'Hello function'
  return function() {
    console.log(msg)
  }
}
const fn = makeFn()
fn()

// 记忆函数
function memoize(f) {
  let cache = {}
  return function() {
    let key = JSON.stringify(arguments)
    cache[key] = cache[key] || f.apply(f, arguments)
    return cache[key]
  }
}
function getArea(r) {
  console.log(r)
  return Math.PI * r * r
}
let getAreaWithMemory = memoize(getArea)
console.log(getAreaWithMemory(4))
console.log(getAreaWithMemory(4))
console.log(getAreaWithMemory(4))

相关文章:

  • C++-容器-string:char到int的转换【Ascii码强转:int(char);‘0‘转为48】【直接转换:char - ‘0‘】
  • JUC之ABA问题
  • 8年测试工程师,3年功能,5年自动化,浅谈我的自动化测试进阶之路...
  • 【架构师(第四十九篇)】 服务端开发之认识 Docker-compose
  • TableLayout布局
  • 现在转行学python,前景和优势有哪些?
  • 生成模型(三):基于流的生成模型(Flow-based model)
  • 游戏要从简单做起
  • 作一回白嫖怪:写一个脚本自动获取ST官网积分,用积分领取奖品
  • kali渗透测试系列---信息收集
  • 学python以后做什么工作
  • Python 的列表方法 append 和 extend 有什么区别?
  • 第27章 MySQL 临时表教程
  • Java项目:springboot私人牙医管理系统
  • SpringBoot系列之整合MyBatis框架
  • 低代码多分支协同开发的建设与实践
  • 是谣传还是真强?GitHub一战封神的“SQL优化手册”获赞过百万
  • 2022年终总结-两年Androider的成长之路
  • URLLC应用场景及未来发展研究
  • rabbitmq基础5——集群节点类型、集群节基础运维,集群管理命令