国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JS函數(shù)式編程(初級)

jk_v1 / 2195人閱讀

摘要:函數(shù)式編程函數(shù)式,可能并不是那么難。在學(xué)習(xí)函數(shù)式編程之初,首先要知道在這一技能葉子中包含有多少個相關(guān)詞,其次要知道它和我們是否從未有過遇見。

JS函數(shù)式編程

函數(shù)式,可能并不是那么難。

在學(xué)習(xí)JS函數(shù)式編程之初,首先要知道在這一“技能葉子”中包含有多少個相關(guān)詞,其次要知道它和我們是否從未有過遇見。

一等公民、純函數(shù)、柯里化、代碼組合、pointfree、命令式與申明式、

Hindley-Milner類型簽名、“特百惠”(Container、functor、Maybe、Either)、lift

Monad(pointed functor、chain)、Applicative Functor

接下來,我將根據(jù)JS函數(shù)式編程說說自己對每個相關(guān)詞的看法。

一等公民(將函數(shù)與數(shù)字做平等對待)
    // 數(shù)字
    var x = 1;
    var y = x;
    
    // 函數(shù), 不平等對待
    var fx = function(x) {
        return x;
    }
    var fy = function(y) {
        return fx(y);
    }
    
    // 函數(shù),平等對待
    // ...
    var fy = fx;

在編程之初,我們就將函數(shù)與其他數(shù)據(jù)類型從思想上分隔開,但在函數(shù)式編程中,我們要摒棄這種思想,將函數(shù)和其他數(shù)據(jù)類型做相等看待

讓我們來看看下面這個是否將函數(shù)當(dāng)做一等公民?

    var fz = function(f){
        return fy(function(y){
            return f(y);
        });
    }

上述代碼讓我們看的很繞是吧,那我們將其轉(zhuǎn)換一下如何?

    var fz = function(f){
        var fx = f;
        return fy(function(y){
            return fx(y)
        })
    }

根據(jù)之前的 fy = fx 等式便可知 function(y){return fx(y)} 其實就是等于 fx 的,所以就可以轉(zhuǎn)化成

    var fz = function(f){
        return fy(f);
    }
    // 同上,fz 即等于 fy
    var fz = fy;

于是乎,這就是一等公民的函數(shù)。思想切莫先入為主。

純函數(shù)

純函數(shù)是一種函數(shù),即相同的輸入,永遠(yuǎn)得到相同的輸出。正如 O = kI + b,IO在數(shù)學(xué)上的函數(shù)關(guān)系。(O: 輸出 , I: 輸入)

函數(shù)式編程追求的是純函數(shù)

    var xs = [1,2,3,4,5];
    // 純
    xs.slice(0,3);
    // => [1,2,3]
    xs.slice(0,3);
    // => [1,2,3]

    // 不純
    xs.splice(0,3);
    // => [1,2,3]
    xs.splice(0,3);
    // => [4,5]
純函數(shù)的好處

可緩存性、可移植性、可測試性、合理性、并行代碼
這些好處都可依據(jù)“純函數(shù)不會隨外部環(huán)境的改變而改變其內(nèi)部運(yùn)算邏輯”而得出。

柯里化(curry)

概念:只傳遞給函數(shù)我們需要傳遞的所有參數(shù)的一部分,讓它返回一個函數(shù)去處理剩下的參數(shù)。

    var add = function(x){
        return function(y){
            return x + y;
        }
    }

    var addOne = add(1);
    var addTen = add(10);

    addOne(2);
    // => 3
    addTen(2);
    // => 12 

柯里化很好的體現(xiàn)了純函數(shù)一個輸入對應(yīng)一個輸出的概念,柯里化就是每傳遞一個參數(shù),就返回一個新函數(shù)處理剩下的參數(shù)

代碼組合

組合(compare), 就像工廠流水線一樣,將多個函數(shù)按順序拼湊,從右到左 依次加工數(shù)據(jù)

    var compare = function(f, g){
        return function(x){
            return f(g(x));
        }
    }

下面是一個反轉(zhuǎn)數(shù)組取第一個元素得到其首字母并大寫的例子

    var reduce = (f) => (arr) => arr.reduce(f)
    var reverse = reduce(function(src, next){return [next].concat(src)}, []);
    var head = (x) => x[0]
    var toUpperCase = (x) => x.toUpperCase();

    // 記住是從右向左
    var f = compare(compare(compare(head,toUpperCase), head), reverse);
    f(["abc","def","ghi"])
    // => G

pointfree就是函數(shù)組合,而這些函數(shù)包含一等公民與柯里化的概念。

申明式與命令式

作個對比就能知道這兩個的區(qū)別了

    // 命令式
    var arr1 = [1,2,3,4,5];
    var arr2 = [];
    for(let i = 0; i < arr1.length; i++) {
        arr.push(arr1[i]);
    }

    // 申明式
    arr2 = arr1.map(function(c){return c;})

命令式是那種一步接著一步的執(zhí)行方式,而申明式是并行運(yùn)算,正如上述的代碼組合的例子一樣,如果我們用命令式來寫肯定是一句一個邏輯,寫起來看起來都很費(fèi)勁,但是申明式不同,它能讓我們只使用一次就可執(zhí)行多條邏輯,而且可以在不同情況環(huán)境下重復(fù)使用,這就是純函數(shù)的可移植性
再看一個例子

    // 命令式
    var headToUpperCase = function(str){
        var h = head(str);
        return h.toUpperCase();
    }

    // 聲明式
    var headToUpperCase = compare(toUpperCase, head);
Hindley-Milner類型簽名

此玩意就是對你構(gòu)造的函數(shù)進(jìn)行一個說明

    // 例一
    // 下面就是Hindley-Milner類型簽名
    // strLength :: String -> Number
    var strLength = function(str){
        return str.length;
    }

    // 例二
    // join :: String -> [String] -> String
    var join = curry(function(what, xs){
        return xs.join(what);
    })
    // curry就是將傳入的函數(shù)參數(shù)轉(zhuǎn)換成curry函數(shù)并返回
    // 第一個String指代what, [string]指代xs,第二個string指代return的值


    // 例三
    // concat :: a -> b -> c
    var concat = curry(function(src, next){
        return src.concat(next);
    })
    // a,b可以用任何字母代替,但不能相同,這樣表示的是不同的類型,而不是從同一數(shù)據(jù)中脫離出來,如去數(shù)組中的某幾個元素組成新的數(shù)組

    // 例四
    // map :: (a -> b) -> [a] -> [b]
    var map = curry(function(f, xs){
        return xs.map(f);
    })
    // a -> b 指代 f ; [a] 指代 xs ; [b] 指代 return 的值

    // 例五
    // reduce :: (a -> b -> a) -> b -> [a] -> b
    var reduce  = curry(function(f, x, xs){
        return xs.reduce(f, x)
    })

下面會介紹兩個functor(Container, Maybe)

Container

先給源碼

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

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

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

使用Container將我們的值進(jìn)行包裹
使用Container.of讓我們不用寫new
使用Container.map讓我們在不訪問__value的情況下得到容器內(nèi)部的值并進(jìn)行運(yùn)算

Maybe

同樣,先給源碼

    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));
    }

Maybe 和 Container其實差不多,唯一的區(qū)別在于它出現(xiàn)了對空值的檢測,讓容器現(xiàn)在能夠存儲空值了。

Either(Left and Right)
先上源碼

    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))
    }

Maybe(null) 一樣,當(dāng)返回一個Left 時就直接讓程序短路,但有了Left 至少可以讓我們用if 做一次條件判斷來知道是什么情況導(dǎo)致輸出Left

lift
一個函數(shù)在調(diào)用的時候,如果被map包裹從一個非functor函數(shù)轉(zhuǎn)換為一個functor函數(shù),就叫做lift。這樣讓普通函數(shù)變成可以操作容器的函數(shù),且兼容任意functor。
以下是例子

    var headToUpperCase = map(compare(toUpperCase, head));
    headToUpperCase(Container.of("hello!"));
IO
    var IO = function(f){
        this.__value = f;
    }
    IO.of = function(){
        return new IO(function(){
            return x;
        })
    }
    IO.prototype.map = function(f){
        return new IO(compose(f, this.__value));
    }

現(xiàn)在this.__value 是一個函數(shù),因而如果執(zhí)行map(head) 等操作時其實是將這個函數(shù)壓入一個“執(zhí)行棧”,而這棧中全部是要執(zhí)行的函數(shù),就想是代碼組合一樣,將所有壓入的函數(shù)延遲執(zhí)行。而看起來,我們?nèi)萜鞯淖罱K形態(tài)就是能容納一個函數(shù)。

那么問題就來了,為什么要用容器,而且最好是容納函數(shù)呢?
函數(shù)式程序即通過管道把數(shù)據(jù)在一系列純函數(shù)間傳遞的程序,而我們之前所有的例子都是關(guān)于同步編碼的,如果出現(xiàn)異步情況怎么辦?如下:

    var fs = require("fs");
    var readFile = function(filename){
        return function(reject, result){
            fs.readFile(filename, "utf-8", function(reject, result){
                err ? reject(err) : result(data);
            })
        }
    }

ok ,這的確使用了函數(shù)式,但異步之后呢,依舊是回調(diào)階梯,所以這么做并沒有真正意義上的使用函數(shù)式。
我們需要延遲執(zhí)行,因而我們需要一個類似IO但并非IO的容器類型,由于能力有限,我只能借用Quildreen Motta 所處理的Folktale 里的Data.Task

    var fs = require("fs");
    var readFile = function(filename){
        return new Task(function(reject, result){
            fs.readFile(filename, "utf-8", function(err, data){
                err ? reject(err) : result(data);
            });
        })
    }
    
    readFile("helloworld").map(split(" ")).map(head).map(toUpperCase).map(head);
    // => Task("H")
Monad

先給例子

    var fs = require("fs");

    // readFile :: String -> IO String
    var readFile = function(filename){
        return new IO(function(){
            return fs.readFileSync(filename, "utf-8");
        })
    }

    // print :: String -> IO String
    var print = function(x){
        return new IO(function(){
            return x
        })
    }

    var hello = compose(map(print), readFile);
    
    hello("helloworld");
    // => IO(IO("helloworld"))

    // 包了兩層IO,于是要想得到值,我們就得執(zhí)行兩次__value
    hello("helloworld").__value().__value();
    // => helloworld

那么如何才能消去這多的層數(shù)呢,我們需要使用join

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

    var ioio = IO.of(IO.of("hello"));
    // => IO(IO("hello"))
    ioio.join();
    // => IO("hello")

于是我們在map 之后就要使用 join ,讓我們將其叫做chain

    var chain = curry(function(f, m){
        return m.map(f).join();
        // or compose(join, map(f))(m)
    })
    
    // map/join
    var hello = compose(join, map(print), readFile);
    
    // chain
    var hello = compose(chain(print), readFile);

    // 給Maybe也加上chain
    Maybe.of(3).chain(function(three){
        return Maybe.of(2).map(add(three))
    })
    // => Maybe(5);
applicative functor

如下實例

    var add = curry(function(x, y){
        return x + y;
    })
    add(Container.of(2), Container.of(3));
    // 很明顯是不能這么進(jìn)行計算的

    // 但是用chain,我們可以
    Container.of(2).chain(function(two){
        return Container.of(3).map(add(two))
    })

可是這看起來挺費(fèi)勁的不是嗎
于是我們就要使用applicative functor

    Container.prototype.ap = function(other_container){
        return other_container.map(this.__value);
    }
    Container.of(2).map(add).ap(Container.of(3));

ap 就是一種函數(shù),能夠把一個functor的函數(shù)值應(yīng)用到另一個functor的值上。
而根據(jù)上述例子,我們可知map 是等價于 of/ap

    F.prototype.map = function(f){
        return this.constructor.of(f).ap(this);
    }

chain 則可以分別得到 functor 和 applicative

    // map
    F.prototype.map = function(){
        var ct = this;
        return ct.chain(function(a){
            return ct.constructor.of(f(a))
        })
    }

    // ap
    F.prototype.ap = function(other){
        return this.chain(function(f){
            return other.map(f);
        })
    }
定律

代碼組合的定律

    // 結(jié)合律
    var _bool = compose(f, compose(g, h)) == compose(compose(f, g), h);
    // => true

map的組合律

    var _bool = compose(map(f), map(g)) == map(compose(f, g))
    // => true

Monad

    // 結(jié)合律
    var _bool = compose(join, map(join)) == compose(join, join)
    // => true

    // 同一律
    compose(join, of) == compose(join, map(of))

    var mcompose = function(f, g){
        return compose(chain(f), chain(g))
    }
    // 左同一律
    mcompose(M, f) == f
    // 右同一律
    mcompose(f, M) == f
    // 結(jié)合律
    mcompose(mcompose(f,g), h) == mcompose(f, mcompose(g, h))

Applicative Functor

    var tOfM = compose(Task.of, Maybe.of);
    tOfM("hello").map(concat).ap(tOfM(" world")));
    // => Task(Maybe(hello world))

    // 同一律
    A.of(id).ap(v) == v

    // 同態(tài)
    A.of(f).ap(A.of(x)) == A.of(f(x))

    // 互換
    var v = Task.of(reverse)
    var x = "olleh"
    v.ap(A.of(x)) == A.of(function(f){return f(x)}).ap(v)

    // 組合
    var u = IO.of(toUpper)
    var v = IO.of(concat(" world"))
    var w = IO.of("hello")

    IO.of(compose).ap(u).ap(v).ap(w) == u.ap(v.ap(w))
參考鏈接

https://www.gitbook.com/book/...

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

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/88354.html

相關(guān)文章

  • 每個 JavaScript 工程師都應(yīng)當(dāng)知道的 10 個面試題

    摘要:在創(chuàng)業(yè)初期,你招來的工程師必須是能夠獨當(dāng)一面的大神隊友。要評估一個應(yīng)聘者的真實水準(zhǔn),最佳方式就是結(jié)對編程。用微博的抓取消息并顯示在時間線上,就是個很好的考察應(yīng)聘者的面試項目。不過結(jié)對編程再好使,也沒辦法讓你完全了解一個應(yīng)聘者。 原文鏈接:10 Interview Questions Every JavaScript Developer Should Know 對大部分公司來說,招聘技...

    weij 評論0 收藏0
  • 初級前端開發(fā)面試總結(jié)

    摘要:前端面試總結(jié)先說背景,本人年月畢業(yè),去年十月校招到今年月一直在做前端開發(fā)工作,年前打算換工作,就重新梳理下面試考點總結(jié)包含基礎(chǔ),基礎(chǔ),常見算法和數(shù)據(jù)結(jié)構(gòu),框架,計算機(jī)網(wǎng)絡(luò)相關(guān)知識,可能有的點很細(xì),有的點很大,參考個人情況進(jìn)行總結(jié),方便對知識 前端面試總結(jié) 先說背景,本人2018年7月畢業(yè),去年十月校招到今年10月一直在做前端開發(fā)工作,年前打算換工作,就重新梳理下面試考點總結(jié)包含: ...

    jifei 評論0 收藏0
  • 初級前端開發(fā)面試總結(jié)

    摘要:前端面試總結(jié)先說背景,本人年月畢業(yè),去年十月校招到今年月一直在做前端開發(fā)工作,年前打算換工作,就重新梳理下面試考點總結(jié)包含基礎(chǔ),基礎(chǔ),常見算法和數(shù)據(jù)結(jié)構(gòu),框架,計算機(jī)網(wǎng)絡(luò)相關(guān)知識,可能有的點很細(xì),有的點很大,參考個人情況進(jìn)行總結(jié),方便對知識 前端面試總結(jié) 先說背景,本人2018年7月畢業(yè),去年十月校招到今年10月一直在做前端開發(fā)工作,年前打算換工作,就重新梳理下面試考點總結(jié)包含: ...

    tigerZH 評論0 收藏0
  • ELSE 技術(shù)周刊(2017.10.23期)

    摘要:為目前使用范圍最廣的網(wǎng)絡(luò)保護(hù)協(xié)議。身處攻擊目標(biāo)周邊的惡意人士能夠利用密鑰重裝攻擊,利用此類安全漏洞。本文和大家一起探討下如何在三年內(nèi)快速成長為一名技術(shù)專家。 業(yè)界動態(tài) Vue 2.5 released Vue 2.5 正式發(fā)布,作者對于該版本的優(yōu)化總結(jié):更好的TypeScript 集成,更好的錯誤處理,更好的單文件功能組件支持以及更好的與環(huán)境無關(guān)的SSR WiFi爆驚天漏洞!KRACK...

    galaxy_robot 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<