函数式编程-函数运算(2)

柯里化

  • 使用柯里化解决上一个案例中硬编码的问题
function checkAge (age) { let min = 18
return age >= min
}
// 普通纯函数
function checkAge (min, age) {
  return age >= min
}
checkAge(18, 24)
checkAge(18, 20)
checkAge(20, 30)
// 柯里化
function checkAge (min) {
  return function (age) {
    return age >= min
} }
// ES6 写法
let checkAge = min => (age => age >= min)
let checkAge18 = checkAge(18) 
let checkAge20 = checkAge(20)
checkAge18(24)
checkAge18(20)
  • 柯里化(Curring):
    • 当一个函数有多个参数的时候先传递一部分参数调用它(这部分参数以后永远不变)
    • 然后返回一个新的函数接收剩余的参数,返回结果

lodash中的柯里化函数

  • _.curry(func)
    • 功能:创建一个函数,该函数接收一个或多个func的参数,如果func所需要的参数都被提供则执行func并返回执行的结果。否则继续返回该函数并等待接收剩余的参数。
    • 参数:需要柯里化的函数
    • 返回值:柯里化后的函数
  • 案例
const _  = require('lodash')

const match = _.curry(function(reg, str){
  return str.match(reg)
})

const haveSpace = match(/\s+/g)
const haveNumber = match(/\d+/g)

console.log(haveSpace('hello world'))
console.log(haveNumber('25$'))

const filter = _.curry(function (func, array) {
  return array.filter(func)
})

console.log(filter(haveSpace, ['John Connor', 'John_Donne']))

const findSpace = filter(haveSpace)
console.log(findSpace(['John Connor', 'John_Donne']))
  • 模拟 _.curry() 的实现
function curry(func) {
  return function curriedFn (...args) {
    // 判断实参和形参的个数
    if(args.length < func.length) {
      return function() {
        return curriedFn(...args.concat(Array.from(arguments)))
      }
    }
    return func(...args)
  }
}

总结

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

函数组合

  • 纯函数和柯里化很容易写出洋葱代码h(g(f(x)))
// 获取数组的最后一个元素再转换成大写字母
_.toUpper(_.first(_.reverse(array)))
  • 函数组合(compose):如果一个函数要经过多个函数处理才能得到最终值,这个时候可以把中间过程的函数合并成一个函数

    • 函数就像是数据的管道,函数组合就是把这些管道连接起来,让数据穿过多个管道形成最终结股票
    • 函数组合默认是从右到左执行
    // 组合函数
    function compose (f, g) {
      return function (x) {
        return f(g(x))
    } }
    function first (arr) {
      return arr[0]
    }
    function reverse (arr) {
      return arr.reverse()
    }
    // 从右到左运行
    let last = compose(first, reverse) 
    console.log(last([1, 2, 3, 4]))
    
  • 函数组合可以让我们把细粒度的函数重新组合生成一个新的函数

  • 模拟实现组合函数方法

// 多函数组合
function compose(...fns) {
  return function (value) {
    return fns.reverse().reduce(function (acc, fn) {
      return fn(acc)
    },value)
  }
}
  • 函数的组合要满足结合律

    • 我们既可以把g和h组合,还可以把f和g组合,结果都是一样的
    // 结合律(associativity)
    let f = compose(f, g, h)
    let associative = compose(compose(f, g), h) == compose(f, compose(g, h)) // true
    

调试

const _ = require('lodash')
const trace = _.curry((tag, v) => { console.log(tag, v)
return v
})
const split = _.curry((sep, str) => _.split(str, sep)) 
const join = _.curry((sep, array) => _.join(array, sep))
const map = _.curry((fn, array) => _.map(array, fn))
const f = _.flowRight(join('-'), trace('map 之后'), map(_.toLower), trace('split 之后'), split(' '))
console.log(f('NEVER SAY DIE'))

Point Free

Point Free:我们可以把数据处理的过程定义成于数据无关的合成运算,不需要用到代表数据的那个参数,只要把简单的运算步骤合成到一起,在使用这种模式之前我们需要定义一些辅助的基本运算函数。

  • 不需要指明处理的数据
  • 只需要合成运算过程
  • 需要定义一些辅助的基本运算函数
const f = fp.flowRight(fp.join('-'), fp.map(_.toLower), fp.split(' '))
  • 案例演示
// 非 Point Free 模式
// Hello World => hello_world function f (word) {
return word.toLowerCase().replace(/\s+/g, '_'); }
// Point Free
const fp = require('lodash/fp')
const f = fp.flowRight(fp.replace(/\s+/g, '_'), fp.toLower) 
console.log(f('Hello World'))
  • 使用 Point Free 的模式,把单词中的首字母提取并转换成大写
const fp = require('lodash/fp')
const firstLetterToUpper = fp.flowRight(join('. '),
fp.map(fp.flowRight(fp.first, fp.toUpper)), split(' '))
console.log(firstLetterToUpper('world wild web'))
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 在前端快速发展的今天,如果不能时刻保持学习就会很快被淘汰。分享一下最近学习的函数式编程的相关知识,希望对大家有所帮...
    gongyexj阅读 4,330评论 0 0
  • #### 函数式编程 #### 函数式编程总结 1. 认识函数式编程 2. 函数复习 (1)函数是一等公民 ...
    爵迹01阅读 3,813评论 0 1
  • 长久以来,面向对象在 JavaScript 编程范式中占据着主导地位。不过,最近人们对函数式编程的兴趣正在增长。函...
    神刀阅读 3,401评论 0 0
  • Swift语言是支持函数式编程的,所以我们需要简单了解一下函数式编程的概念. 在了解函数式编程的概念之前呢,先看看...
    小心韩国人阅读 4,086评论 0 0
  • Study Notes[https://wuner.gitee.io/wuner-notes/fed-e-task...
    Wuner阅读 3,860评论 0 0

友情链接更多精彩内容