成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

函數(shù)式編程 - 容器(container)

Anchorer / 3253人閱讀

摘要:函子上面容器上定義了方法,的定義也類似是實(shí)現(xiàn)了函數(shù)并遵守一些特定規(guī)則的容器類型。不同類型的函子容器在處理內(nèi)部值時(shí),經(jīng)常遇到傳入?yún)?shù)異常的情況的情況,檢查值的合理性就非常重要。函子保證在調(diào)用傳入的函數(shù)之前,檢查值是否為空。

最近一直在學(xué)習(xí)函數(shù)式編程,前面介紹了函數(shù)式編程中非常重要的兩個(gè)運(yùn)算函數(shù)柯里化 和 函數(shù)組合,下文出現(xiàn)的currycompose函數(shù)可以從前兩篇文章中找到。它們都可以直接在實(shí)際開發(fā)中用到,寫出函數(shù)式的程序。

本文主要初探容器的相關(guān)概念,以及如何處理編程中異步操作,錯(cuò)誤處理等依賴外部環(huán)境狀態(tài)變化的情況,,

容器(container)

容器可以想象成一個(gè)瓶子,也就是一個(gè)對(duì)象,里面可以放各種不同類型的值。想想,瓶子還有一個(gè)特點(diǎn),跟外界隔開,只有從瓶口才能拿到里面的東西;類比看看, container 回暴露出接口供外界操作內(nèi)部的值。

一個(gè)典型的容器示例:

    var Container = function(x) {
        this.__value = x;
    }
    
    Container.of = function(x) {
        return new Container(x);
    }
    
    Container.of("test")   
    // 在chrome下會(huì)打印出 
    // Container?{__value: "test"}  

我們已經(jīng)實(shí)現(xiàn)了一個(gè)容器,并且實(shí)現(xiàn)了一個(gè)把值放到容器里面的 Container.of方法,簡(jiǎn)單看,它像是一個(gè)利用工廠模式創(chuàng)建特定對(duì)象的方法。of方法正是返回一個(gè)container。

函子(functor)

上面容器上定義了of方法,functor的定義也類似

Functor 是實(shí)現(xiàn)了map函數(shù)并遵守一些特定規(guī)則的容器類型。

把值留在容器中,只能暴露出map接口處理它。函子是非常重要的數(shù)據(jù)類型,后面會(huì)講到各種不同功能的函子,對(duì)應(yīng)處理各種依賴外部變量狀態(tài)的問題。

Container.prototype.map = function(f) {
    return Container.of(f(this.__value))
}

把即將處理容器內(nèi)變量的函數(shù),包裹在map方法里面,返回的執(zhí)行結(jié)果也會(huì)是一個(gè)Container。
這樣有幾點(diǎn)好處:

保證容器內(nèi)的value一直不會(huì)暴露出去,

對(duì)value的操作方法最終會(huì)交給容器執(zhí)行,可以決定何時(shí)執(zhí)行。

方便鏈?zhǔn)秸{(diào)用

    // 利用上一篇中講到的柯里化,就可以看出其特性。
    var add2 = function(x, y) {
        return x + y;
    };
    
    curriedAdd = curry(add2);
    
    Container.of(2).map(curriedAdd(3));
    // Container?{__value: 5}
不同類型的函子 maybe

容器在處理內(nèi)部值時(shí),經(jīng)常遇到傳入?yún)?shù)異常的情況的情況,檢查value 值的合理性就非常重要。Maybe 函子保證在調(diào)用傳入的函數(shù)之前,檢查值是否為空。

var Maybe = function(x) {
  this.__value = x;
}

Maybe.of = function(x) {
  return new Maybe(x);
}

Maybe.prototype.isNothing = function() {
  return (this.__value === null || this.__value === undefined);
}

Maybe.prototype.map = function(f) {
  return this.isNothing() ? Maybe.of(null) : Maybe.of(f(this.__value));
}
   

這個(gè)通用的例子,體現(xiàn)了輸出結(jié)果的不確定性,也可以看出,在容器內(nèi)部所有對(duì)value值的操作,都會(huì)交給容器來執(zhí)行。在value 為空的情況下,也會(huì)返回包裹著null的容器,避免后續(xù)容器鏈?zhǔn)秸{(diào)用報(bào)錯(cuò)。

異常捕獲函子

通常 使用throw/catch就可以捕獲異常,拋出錯(cuò)誤,但它并不是一種純函數(shù)方法,最好的方法是在出現(xiàn)異常時(shí),可以正常返回信息。Either函子,內(nèi)部?jī)蓚€(gè)子類Leftright; 可以看成右值是正常情況下使用并返回的值,左值是操作簡(jiǎn)單的默認(rèn)值。

var Left = function(x) {
  this.__value = x;
}

Left.of = function(x) {
  return new Left(x);
}

Left.prototype.map = function(f) {
  return this;
}

var Right = function(x) {
  this.__value = x;
}

Right.of = function(x) {
  return new Right(x);
}

Right.prototype.map = function(f) {
  return Right.of(f(this.__value));
}

// 輸入數(shù)據(jù)進(jìn)行校驗(yàn)
var setage = function(age) {
     return typeof age === "number"? Right.of(age): Left.of("error age")
}

setage(12).map(function(age){return "my age is" + age})
// Right?{__value: "my age is12"}
setage("age").map(function(age){return "my age is" + age})
// Left?{__value: "error age"}

leftright 唯一的區(qū)別在于map 方法的實(shí)現(xiàn),當(dāng)然,一個(gè)函子最大的特點(diǎn)也體現(xiàn)在map方法上,
Left.map 不管傳入的是什么函數(shù),直接返回當(dāng)前容器;Right.map則是示例里面的方法一樣。

IO 操作

IO 操作本身就是不純的操作,生來就得跟外界環(huán)境變量打交道,不過可以掩蓋他的不確定性。跟下面localStorage包裹函數(shù)類似,延遲執(zhí)行IO 操作。

 var getStorage = function(key) {
    return function() {
        return localStorage[key];
    }
}

再看看,封裝了高級(jí)一點(diǎn)的IO 函子:

    var IO = function(f) {
        this.__value = f;
    }
    
    IO.of = function(x) {
        return new IO(function(){
            return x;
        })
    }
    
    IO.prototype.map = function(f) {
        // 使用上一句定義的compose函數(shù)
        return new IO(compose(f, this.__value))
    }

compose函數(shù)組合,里面存放的都是函數(shù),this.__value跟其他函子內(nèi)部值不同,它是函數(shù)。IO.of方法在new對(duì)象之前,把值包裹在函數(shù)里面,試圖延遲執(zhí)行。

  // 測(cè)試一下
var io__dom= new IO(function() {return window.document})

io__dom.map(function(doc) { return doc.title})

// IO?{__value: ?}

返回一個(gè)沒有執(zhí)行的函數(shù)對(duì)象,里面的__value值對(duì)應(yīng)的函數(shù),在上面函數(shù)調(diào)用后并沒有執(zhí)行,只有在調(diào)用了this.__value值后,才執(zhí)行。最后一步不純的操作,交給了函數(shù)調(diào)用者去做。

Monad

一個(gè)functor, 只要他定義了一個(gè)join 方法和一個(gè)of 方法,那么它就是一個(gè)monad。 它可以將多層相同類型的嵌套扁平化,像剝洋蔥一樣。關(guān)鍵在于它比一般functor 多了一個(gè)join 方法。 我們先看看剝開一層的join方法。

    var IO = function(f) {
        this.__value = f
    }
    
    IO.of = function(x) {
        return new IO(function(){
            return x;
        })
    }
    
    IO.prototype.join = function() {
        return this.__value ? this.__value(): IO.of(null);
    }
    // 包裹上兩層
    var foo = IO.of(IO.of("test bar"));
    foo.join().__value();
    // 返回里面嵌套著的IO類。 IO?{__value: ?},接著只需調(diào)用這里的__value(),就可以返回字符串`test bar`;

回頭看看前面map方法,return new IO(),生成新的容器,方便鏈?zhǔn)秸{(diào)用,跟 join方法結(jié)合一起使用,生成容器后,再扁平化。形成 chain 函數(shù)

  var  chain = curry(function(f, m) {
        return m.map(f).join();
    })

看一個(gè)完整示例,其中curry 和compose,分別用到了鏈接里面的實(shí)現(xiàn),:

var IO = function(f) {
  this.__value = f;
}

IO.of = function(x) {
  return new IO(function() {
    return x;
  })
}

IO.prototype.map = function(f) {
  // 使用上一句定義的compose函數(shù)
  return new IO(compose(f, this.__value))
}

IO.prototype.join = function() {
  return this.__value ? this.__value() : IO.of(null);
}

var chain = curry(function(f, m) {
  return m.map(f).join();
})

var log = function(x) {
  return new IO(function() {
    console.log(x);
    return x;
  })
}

var setStyle = curry(function(sel, props) {
  return new IO(function() {
    return document.querySelector(sel).style.background = props
  })
})

var getItem = function(key) {
  return new IO(function() {
    return localStorage.getItem(key);
  })
};

var map = curry(function(f, functor) {
  return functor.map(f);
});

// 簡(jiǎn)單實(shí)現(xiàn)join
var join = function(functor) {
  return functor.join();
}

localStorage.background = "#000";

var setItemStyle = compose(join, map(setStyle("body")), join, map(log), getItem);

// 換成 鏈?zhǔn)秸{(diào)用。
setItemStyle = compose(chain(setStyle("body")), chain(log), getItem);

setItemStyle("background").__value(); // 操作dom 改變背景顏色

總結(jié)

本文主要利用簡(jiǎn)單代碼舉例,介紹了容器,函子等相關(guān)概念,初步認(rèn)識(shí)了各種不同的函子。深入實(shí)踐示例,可以參考閱讀下面鏈接:

函數(shù)式編程風(fēng)格

js函數(shù)式編程指南https://llh911001.gitbooks.io...

JavaScript函數(shù)式編程(二)

JavaScript:函數(shù)式編程基本概念學(xué)習(xí)

JS函數(shù)式編程 - 函子和范疇論

javascript函數(shù)式編程之 函子(functor)

函數(shù)式編程入門教程

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/102475.html

相關(guān)文章

  • 函數(shù)編程(五)

    摘要:前面我們已經(jīng)知道如何書寫函數(shù)式的程序了,但是我們還沒提到控制流異常處理異步操作和狀態(tài)呢容器容器為函數(shù)式編程里普通的變量對(duì)象函數(shù)提供了一層極其強(qiáng)大的外衣,賦予了它們一些很驚艷的特性按照我們的慣例,先從最簡(jiǎn)單的容器入手。 如果你前面都看完了跟到了這里,我只能說你很棒棒,不過我不得不說,這才剛剛開始。前面我們已經(jīng)知道如何書寫函數(shù)式的程序了,但是我們還沒提到控制流(control flow)、...

    qqlcbb 評(píng)論0 收藏0
  • JavaScript函數(shù)編程(二)

    摘要:函數(shù)式編程二拖延癥了好久,第二篇終于寫出來了。如果你對(duì)熟悉的話應(yīng)該還記得,是可以調(diào)用來集中處理錯(cuò)誤的對(duì)于函數(shù)式編程我們也可以做同樣的操作,如果運(yùn)行正確,那么就返回正確的結(jié)果如果錯(cuò)誤,就返回一個(gè)用于描述錯(cuò)誤的結(jié)果。 JavaScript函數(shù)式編程(二) 拖延癥了好久,第二篇終于寫出來了。 上一篇在這里:JavaScript函數(shù)式編程(一) 上一篇文章里我們提到了純函數(shù)的概念,所謂的純函數(shù)...

    booster 評(píng)論0 收藏0
  • Js-函數(shù)編程

    摘要:組合組合的功能非常強(qiáng)大,也是函數(shù)式編程的一個(gè)核心概念,所謂的對(duì)過程進(jìn)行封裝很大程度上就是依賴于組合。在理解之前,先認(rèn)識(shí)一個(gè)東西概念容器容器為函數(shù)式編程里普通的變量對(duì)象函數(shù)提供了一層極其強(qiáng)大的外衣,賦予了它們一些很驚艷的特性。 前言 JavaScript是一門多范式語(yǔ)言,即可使用OOP(面向?qū)ο螅?,也可以使用FP(函數(shù)式),由于筆者最近在學(xué)習(xí)React相關(guān)的技術(shù)棧,想進(jìn)一步深入了解其思想...

    whinc 評(píng)論0 收藏0
  • JavaScript 函數(shù)真正的淺析

    摘要:入門的導(dǎo)語(yǔ)廢話最近兩年你要說函數(shù)式編程不火的話那是不可能的是人都知道函數(shù)式編程很火為什么函數(shù)式編程會(huì)火呢在于它的思想很強(qiáng)大很強(qiáng)勢(shì)尤其是前端的更是在上完全使用純函數(shù)函數(shù)式的好處漸漸被發(fā)掘出來筆者最近看了一些函數(shù)式方面的東東現(xiàn)在發(fā)出來給大家學(xué)習(xí) 0x00 入門的導(dǎo)語(yǔ)(廢話) 最近兩年你要說函數(shù)式編程不火的話, 那是不可能的, 是人都知道函數(shù)式編程很火.為什么函數(shù)式編程會(huì)火呢, 在于它的思想...

    fox_soyoung 評(píng)論0 收藏0
  • JS函數(shù)編程(初級(jí))

    摘要:函數(shù)式編程函數(shù)式,可能并不是那么難。在學(xué)習(xí)函數(shù)式編程之初,首先要知道在這一技能葉子中包含有多少個(gè)相關(guān)詞,其次要知道它和我們是否從未有過遇見。 JS函數(shù)式編程 函數(shù)式,可能并不是那么難。 在學(xué)習(xí)JS函數(shù)式編程之初,首先要知道在這一技能葉子中包含有多少個(gè)相關(guān)詞,其次要知道它和我們是否從未有過遇見。 一等公民、純函數(shù)、柯里化、代碼組合、pointfree、命令式與申明式、 Hindley...

    jk_v1 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

Anchorer

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<