美文网首页
函数式编程小思考4.2 笔记

函数式编程小思考4.2 笔记

作者: wudimingwo | 来源:发表于2019-01-06 15:33 被阅读0次

    函数式编程小思考4 笔记
    JS函数式编程指南
    Data.Task 函子 源码

    补充两个内容

    1. 用得到的curry函数

    2. 文中提及的一些定律,定理什么的

    3. 用得到的curry函数

        var memoize = function(f) {
                    var cache = {};
    
                    return function() {
                        var arg_str = JSON.stringify(arguments);
                        cache[arg_str] = cache[arg_str] || f.apply(f, arguments);
                        return cache[arg_str];
                    };
                };
    
                function sub_curry(fn /*, variable number of args */ ) {
                    var args = [].slice.call(arguments, 1);
                    return function() {
                        return fn.apply(this, args.concat(toArray(arguments)));
                    };
                }
    
                function curry1(fn, length) {
                    // capture fn's # of parameters
                    length = length || fn.length;
                    return function() {
                        if(arguments.length < length) {
                            // not all arguments have been specified. Curry once more.
                            var combined = [fn].concat(toArray(arguments));
                            return length - arguments.length > 0 ?
                                curry(sub_curry.apply(this, combined), length - arguments.length) :
                                sub_curry.call(this, combined);
                        } else {
                            // all arguments have been specified, actually call function
                            return fn.apply(this, arguments);
                        }
                    };
                }
    
                var compose = function() {
                    let args = [].slice.call(arguments);
                    let len = args.length - 1;
                    return function(data) {
                        let result = args[len](data);
                        while(len--) {
                            result = args[len](result);
                        }
                        return result;
                    }
                }
    
                // 应用lodash里的curry
                let curry = _.curry;
    
                var match = curry(function(what, str) {
                    return str.match(what);
                });
    
                var replace = curry(function(what, replacement, str) {
                    return str.replace(what, replacement);
                });
    
                var filter = curry(function(f, ary) {
                    return ary.filter(f);
                });
    
                var map = curry(function(f, ary) {
                    return ary.map(f);
                });
                var split = curry(function(what, str) {
                    return split(what, str)
                })
                var reduce = curry(function(f, init, arr) {
                    return arr.reduce(f, init)
                })
                var slice = curry(function(start, end, arr) {
                    return arr.slice(start, end);
                })
    
                var toLowerCase = function(str) {
                    return str.toLowerCase();
                }
    
                var join = curry(function(what, arr) {
                    return arr.join(what)
                })
    
                var concat = curry(function(what, str) {
                    return str.concat(what)
                })
    
                var prop = curry(function(prop, obj) {
                    return obj[prop]
                })
    
                var maybe = curry(function(x, f, m) {
                    return m.isNothing() ? x : f(m.__value);
                });
    
                //  map :: Functor f => (a -> b) -> f a -> f b
                var map = curry(function(f, Container) {
                    return Container.map(f);
                });
    
                var id = function(x) {
                    return x;
                };
    
                var of = curry(function(m, x) {
                    return m.of(x)
                })
    
                var trace = _.curry(function(tag, x) {
                    console.log(tag, x);
                    return x;
                });
    
                // 第一种容器
                var Container = function(x) {
                    this.__value = x;
                }
    
                Container.of = function(x) {
                    return new Container(x);
                };
    
                // (a -> b) -> Container a -> Container b
                Container.prototype.map = function(f) {
                    return Container.of(f(this.__value))
                }
    
                Container.of("bombs").map(concat(' away')).map(prop('length'))
                //=> Container(10)
    
                //观察这句代码, 他与 compose 有点类似,
                // compose是从右向左, 而map 是 从左向右
                // compose 是把 return 出来的值, 传递给下一个函数的 参数入口
                // 而 map 是return 一个 容器, 用调用的方式, 把参数传进去.
                // 当然两者有很明显的不同
                // compose 返回的是函数, compose的执行本身 实际上是延迟执行, 预留出一个参数入口
                // 而在上面这种情况, 使用map的时候, 实际上参数值已经确定, 并且功能已经执行,
                // 不存在延迟执行.
    
                // 这种链式调用方式, 作者似乎称之为 点记法(dot notation syntax)
    
                // 第二种容器
                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));
                }
    
                var maybe = curry(function(x, f, m) { // 出错时返回自定义的信息, 不执行 f, 
                    return m.isNothing() ? x : f(m.__value);
                });
    
                // 第三种容器 Either
                var Left = function(x) {
                    this.__value = x;
                }
    
                Left.of = function(x) {
                    return new Left(x);
                }
                // 这又是一种奇特的 map, Left容器遇到多少个map, 多少个 f, 返回的都是同样的值,
                // 让所有f都失效.
                // 这根 Maybe.of(null) 稍微不同.虽然Maybe.of(null) 的 map 也会让所有的map,f都失效.
                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));
                }
    
                //  getAge :: Date -> User -> Either(String, Number)
                var getAge = curry(function(now, user) {
                    var birthdate = moment(user.birthdate, 'YYYY-MM-DD');
                    if(!birthdate.isValid()) return Left.of("Birth date could not be parsed");
                    return Right.of(now.diff(birthdate, 'years'));
                });
    
                //  either :: (a -> c) -> (b -> c) -> Either a b -> c
                var either = curry(function(f, g, e) {
                    switch(e.constructor) {
                        case Left:
                            return f(e.__value);
                        case Right:
                            return g(e.__value);
                    }
                });
    
                //  zoltar :: User -> _
                //          var zoltar = compose(console.log, either(id, fortune), getAge(moment()));
                //
                //          zoltar({
                //              birthdate: '2005-12-12'
                //          });
                //          // "If you survive, you will be 10"
                //          // undefined
                //
                //          zoltar({
                //              birthdate: 'balloons!'
                //          });
                // "Birth date could not be parsed"
                // undefined
    
                var IO = function(f) {
                    this.__value = f;
                }
    
                IO.of = function(x) {
                    return new IO(function() {
                        return x;
                    });
                }
    
                IO.prototype.map = function(f) {
                    return new IO(_.compose(f, this.__value));
                }
                var IO = function(f) {
                    this.unsafePerformIO = f;
                }
    
                IO.prototype.map = function(f) {
                    return new IO(_.compose(f, this.unsafePerformIO));
                }
    
                // monad
                Maybe.prototype.join = function() {
                    return this.isNothing() ? Maybe.of(null) : this.__value;
                }
    
                var join = function(m) {
                    return m.join();
                }
    
                // 对其他类型容器都是一样的
                IO.prototype.join = function() {
                    return this.unsafePerformIO();
                }
    
                //  chain :: Monad m => (a -> m b) -> m a -> m b
                var chain = curry(function(f, m) {
                    return m.map(f).join(); // 或者 compose(join, map(f))(m)
                });
    
                Container.prototype.ap = function(other_container) {
                    return other_container.map(this.__value);
                }
    
                // 从 chain/of 衍生出的 map
                X.prototype.map = function(f) {
                    var m = this;
                    return m.chain(function(a) {
                        return m.constructor.of(f(a));
                    });
                }
    
                // 从 chain/map 衍生出的 ap
                X.prototype.ap = function(other) {
                    return this.chain(function(f) {
                        return other.map(f);
                    });
                };
    
                X.prototype.chain = function(f) {
                    return f(this.__value)
                }
    
                X.of = function(x) {
                    return new X(x)
                }
                X.prototype.map = function(f) {
                    return X.of(f(this.__value))
                }
                X.prototype.ap = function(m) {
                    return m.map(this.__value);
                }
    
                X.prototype.join = function() {
                    return this.__value;
                }
                X.prototype.chain = function(f) {
                    return this.map(f).join();
                }
    
    1. 文中提及的一些定律,定理什么的
                /* compose 结合律 */
                /* var associative = compose(f, compose(g, h)) == compose(compose(f, g), h); */
    
                var id = function(x) {
                    return x;
                };
    
                // identity
                map(id) === id;
    
                // composition
                compose(map(f), map(g)) === map(compose(f, g));
    
                /* 任何时候都成立 , 满足单位律*/
                // compose(id, f) == compose(f, id) == f;
    
                // map 的组合律
                var law = compose(map(f), map(g)) == map(compose(f, g));
    
                // 同一律
                let id = function(x) {
                    return x
                }
                let map1 = curry(function(f, arr) {
                    return arr.map(f);
                })
                let map2 = curry(function(f, container) {
                    return Container.of(f(container.__value));
                })
                var id1 = map1(id) // 返回的是一个函数
                var id2 = map2(id) // 返回的也是一个函数
                // 没错 无论是id ,id1,id2 哪个函数接收一个容器时, 都会返回同样的容器.
                // 当然 id1 应该接收的是 数组, id2接收的是个容器, 而id 则能接收任何类型
    
                //同一律
                map(id) === id; // 这两个函数的效果是完全相同的, 但实际上是两个引用值,所以不可能绝对相等.
    
                // map 的组合律 var law = compose(map(f), map(g)) == map(compose(f, g));
    
                //          //自由定理 第一遍读的时候,不是很懂, 现在再读一遍, 比第一遍要有所理解, 但还是不太懂.
                // 主要还是适用范围问题.
                // 根据上面 map compose 的h 组合律 就能知道, map这类函数有很特别的地方.
    
                // head :: [a] -> a 
                compose(f, head) == compose(head, map(f));
                // filter :: (a -> Bool) -> [a] -> [a] 
                compose(map(f), filter(compose(p, f))) == compose(filter(p), map(f));
    
                // 关于这个map函数, 之前接触数组的map时, 语义上给我感觉是
                // 遍历数组, 打开数组的含义, 使用顺序在感觉上, 是先确定要遍历的数组, 然后再确定要使用的功能
                // 而在curry化之后的 map 给我的语义上的感觉是, 一个函数可以通过map 包装之后,能够打开数组.
                // 这跟我之前自己胡乱总结多层函数嵌套时, 总结出的 函数工厂非常类似,
                // 如果用函数工厂的角度去看,就是, 一个函数经过 map的函数工厂加工后, 可以处理数组了.
                // 相当的, 非常的, 神奇.
    
                // 当然,我们不要跑题
                // 上面的例子中, 可以看出 head能够打开操作数组, map,filter 也都能打开操作数组.
                // 由此, 我们可以合理猜测, 自由定理的适用条件是, 处理数组时,专用?
                // (还是说, 是之前的猜测, 是因为高阶函数的原因?)
                // 做好标记, 也许看第三遍的时候, 也许能理解的更多.
                
                
                  // 结合律
      compose(join, map(join)) == compose(join, join)
      // 这个返回的函数 接收的数据类型, 天然的是两层嵌套以上的容器.
      // 总结果是, 脱了两层容器
      // 左边是先脱里层的,再脱外层的
      // 右边是先脱外层的,再脱里层的
      
        // 同一律 (M a)
      compose(join, of) == compose(join, map(of)) == id
      // 接收一个 容器, 再接收一个值.
      // 
                var of = curry(function (m,x) { // 辅助理解
                    return m.of(x)
                })
    //              
     
     
       var mcompose = function(f, g) {
        return compose(chain(f), chain(g));
      }
       // 首先, mcompose 接收的参数类型是 容器
       // 其次, 无论是 f,还是g 都会把返回值放进容器当中.
       // 这是使用mcompose的前提条件, 或者也可以认为是 全都使用这种规范的 compose
       
       // 如果只是普通函数, 我们直接用compose
       // 如果函数需要放进容器中, 但返回值是正常值, 我们就选择 IO容器
       // 即IO容器的 map 能够完成compose
       // 但有个要求是, IO容器里的值必须全都是是函数. 任何值或功能,操作都要包裹进函数中.
       
       // 如果 f,g需要把返回值放进容器当中
       // 此时还想用 compose效果, 
       // 就可以用mcompose,
       // mcompose
    
      // 左同一律
      mcompose(M, f) == f
      // 这个M是什么? 根据上面的用过这个符号来讲, M是一个容器
      // 但根据mcompose来讲, M应该是个函数.
    
      // 右同一律
      mcompose(f, M) == f
        // 这两个 到底是什么意思
        // 实在是想不出 这个M 到底什么意思
    
        
      // 结合律
      mcompose(mcompose(f, g), h) == mcompose(f, mcompose(g, h))
      // 这个还算比较好理解
      
      
      F.of(x).map(f) == F.of(f).ap(F.of(x))
      
      // 同一律
      // 此处的v 是一个带有值的 容器
    A.of(id).ap(v) == v
    
    // 同态
    A.of(f).ap(A.of(x)) == A.of(f(x))
    
    // 互换
    v.ap(A.of(x)) == A.of(function(f) { return f(x) }).ap(v)
    // 这个很有启发意义有没有?!
    // 左边表示, 一个函数找到一个值
    // 右边表示, 一个值找到一个函数. 值放进一个函数中, 另一个函数当做参数被调用进来.
    // 玩得真是太溜了
    
    // 组合
    A.of(compose).ap(u).ap(v).ap(w) == u.ap(v.ap(w));
    //例子
    var u = IO.of(_.toUpper);
    var v = IO.of(_.concat("& beyond"));
    var w = IO.of("blood bath ");
    
    IO.of(_.compose).ap(u).ap(v).ap(w) == u.ap(v.ap(w))
    //似乎只适用于 IO?
    

    相关文章

      网友评论

          本文标题:函数式编程小思考4.2 笔记

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