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

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

一些约束

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

纯函数

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)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容