美文网首页
函数式编程学习过程中的一些总结

函数式编程学习过程中的一些总结

作者: 夏尔先生 | 来源:发表于2017-04-01 10:19 被阅读109次

最近在学习函数式编程,记录了一些笔记,也总结了一些自己的理解。我准备整理一下陆陆续续发出来,本文不算是一篇文章吧,算是自己在学习函数式编程中的一些总结,也算一个引子。

一些约束

  • 不要为了延迟执行,而简单地用一个函数把另一个函数包起来。
  • 参数命名的时候,不要把参数名限制在特定的数据上,容易造成重复造轮子。
  • 函数不依赖外部值

纯函数

1.概念

函数式编程中函数是一等公民,即普通人。对于函数,强调纯函数的概念。什么是纯函数呢?

纯函数是这样一种函数,相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用。

比较明显的一个例子就是slice和splice。前者纯而后者不纯,想想为什么~

这里说的没有副作用具体是什么呢?像上面我提到的splice,它的副作用就是修改了本来的数据,还有一些容易想到的情况,如向数据库插入了数据,打印了数据,获取了用户输入等。 总之,就是一切跟函数外部环境反生交互的行为。

归根结底,这些行为很容易导致“相同的输入返回相同的结果”这一概念的失效。这也是我们尽量避开它们的原因。

2.为什么追求纯?

为什么要花这么多力气去实现纯函数呢,可见的几点好处如下:

可缓存性(Cacheable)

重复的计算不需要多次计算,这就是可缓存性。


let addFive = memoize(x=>x+5)

addFive(1); 
addFive(1);
addFive(1); 
//真正的计算只会发生一次。

memoize的实现很简单,使用一个对象来存储计算过的值即可。下面是一个简单的实现


const momize=(func)=>{
    //cache对象用于存储计算过的值
    let cache={}
    
    return ()=>{
        let key = JSON.stringify(arguments)
        if(!cache[key]){
            cache[key] = func.apply(this,arguments)
        }
        
        return cache[key]
    }
}

可移植性(Portable)

纯函数的依赖很明确,需要的数据都在参数中体现了。这样做,使应用更加灵活。因为一切的依赖都参数化了,当依赖变化时,直接把新的依赖传递进去就好了。

可测试性(Testable)

这也是可以预见的,相同的输入具有相同的输出。意味着测试时我们只需要给函数一个输入,然后断言它的输出即可。

引用透明(referential transparency)

函数的返回值只依赖于它的输入,这就是引用透明性。很明显,纯函数具有这个特性。这个特性可以帮助我们更好的分析我们的程序。

并行

纯函数可以任意并行的运行。因为纯函数没有副作用,不会和其它纯函数进入竞争状态。也不需要访问共享的内存。

柯里化

对于函数式编程来说,柯里化是一个不可或缺的工具。它的概念很简单,只传递给函数一部分参数来调用它,返回一个接受剩下参数的函数。
一个被举得最多的例子:


const addFunc =(a,b,c,d)=>{
    return a+b+c+d;
}

const add = curry(addFunc)

add(1)(2)(3)(4)   //10
add(1,2)(3,4)     //10
add(1,2,3,4)      //10

经过柯里化,现在我们不需要再一次性的将所有参数传入了。

代码组合(compose)

之前我有一篇文章分析过redux的源码,其中有一个文件compose.js:


export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  return funcs.reduce((a, b) => (...args) => a(b(...args)))  
}

这就是组合函数,一个函数的返回将作为另一个函数的输入。

PS:这个代码是从左往右运行的,函数式推荐从右向左运行。据说这样更加能够反映数学上的含义。
通过组合,我们可以像搭积木一样把简单的功能拼凑成复杂的功能。

pointfree

这是一种风格,指的是数据无关,就像上面的compose,举个例子:


//非pointfree 风格
let upperReplace=(arg)=>{
    return arg.toUpperCase().replace(/\s+/ig/,'_')
}

//pointfree风格
let upperReplace = compose(replace(/\s+/ig/,'_'),toUpperCase)

非常明显,非pointfree模式提到了数据arg,而pointfree没有。可以看出pointfree还能帮我们减少不必要的命名,我相信你们也和我一样觉得命名是一件头疼的事。

debug

使用组合有时容易出错,比如参数个数对应不上之类的。对于组合有一种比较实用但不纯的方法来追踪代码的执行情况。


let trace = curry((tag,x)=>{
    console.log(tag,x);
    return x;
})

//将trace放在合适的地方,就可以看到该处的日志,从而纠错
let test = compose(otherOper,trace("after toUpper"),toUpper,firstEle,reverse)

相关文章

  • 函数式编程学习过程中的一些总结

    最近在学习函数式编程,记录了一些笔记,也总结了一些自己的理解。我准备整理一下陆陆续续发出来,本文不算是一篇文章吧,...

  • Javascript进阶——函数式编程思想

    什么是函数式编程? 在学习函数式编程之前,我们先来了解一些与之相关的概念,以便于我们更好的理解函数式编程思想: 命...

  • 函数式编程学习笔记

    函数式编程 函数式编程的核心思想是把运算过程抽象成函数,编程过程中面向函数进行编程 一、纯函数:相同的输入永远会得...

  • 函数响应式编程概述

    什么是编程? 面向过程 vs 面向对象 命令式编程 vs 函数式编程 函数响应式编程 满足函数式的一些特性 面向离...

  • 函数式编程

    为什么学习函数式编程 函数式编程随着react的流行受到越来越多的关注 vue3也开始拥抱函数式编程 函数式编程可...

  • 函数式编程

    1 文章目标 为什么要学习函数式编程以及什么是函数式编程 函数式编程的特性(纯函数、柯里化、函数组合等) 函数式编...

  • 函数式编程

    拉勾大前端的笔记,仅作为学习记录 课程介绍 为什么学习函数式编程,以及什么是函数编程 函数式编程的特性(纯函数,柯...

  • Scala 学习笔记

    Scala 学习笔记 1.函数式编程 函数式编程:函数式编程把函数当作一等公民,充分利用函数,支持函数的多种使用方...

  • Python进阶语法——函数式编程、模块,面向对象

    一、 Python进阶学习 一、函数式编程 1.1函数式编程 1.2高阶函数 1.2.1 import mathd...

  • Haskell学习-函数式编程初探

    原文地址:Haskell学习-函数式编程初探  为什么要学习函数式编程?为什么要学习Haskell?  .net到...

网友评论

      本文标题:函数式编程学习过程中的一些总结

      本文链接:https://www.haomeiwen.com/subject/dlfiottx.html