zoukankan      html  css  js  c++  java
  • [Functional Programming] Working with two functors(Applicative Functors)-- Part1 --.ap

    What is applicative functor:

    the ability to apply functors to each other.

    For example we have tow functors: Container(2), Container(3)

    // We can't do this because the numbers are bottled up.
    add(Container.of(2), Container.of(3));  // NaN

    We cannot just add two functors!

    Instead we should do:

    const map = (fn, m) => m.map(fn);
    const containerOfAdd2 = map(add(3), Container.of(2)); // Container(5)

    or

    Container.of(2).chain(two => Container.of(3).map(add(two)));

    Previous solution should work. but there are better way to do it:

    1. ap

    Container.prototype.ap = function (otherContainer) {
      return otherContainer.map(this.$value);
    };

    As you can see, 'ap' takes a fuctor then applya map to it.

    We can see ap:

    Container.of(2).map(add).ap(Container.of(3)); // Container(5)

    Or, we add lift 'add(2)' into Container, then apply Container(3):

    Container.of(add(2)).ap(Container.of(3)); // Container(5)

    Because 'add' is partially  applied in add(2), when doing '.ap(Container.of(3))', we give the rest input '3' to it.

    Now, we can define applicative functor in programming language:

    An applicative functor is a pointed functor with an ap method

    Note the dependence on pointed

    Laws behind:

    F.of(x).map(f) === F.of(f).ap(F.of(x))

    Main idea is: lift 'f' (function) into Functor, then 'ap' (apply) another Functor with the value (x).

    Some example:

    Maybe.of(add).ap(Maybe.of(2)).ap(Maybe.of(3)) // Just(5)
    Task.of(add).ap(Task.of(2)).ap(Task.of(3)) // Task(5)

    Equals:

    Maybe.of(add(2)).ap(Maybe.of(3)) // Just(5)
    Task.of(add(2)).ap(Task.of(3)) // Task(5)

    More examples:

    // Http.get :: String -> Task Error HTML
    
    const renderPage = curry((destinations, events) => { /* render page */ });
    
    Task.of(renderPage).ap(Http.get('/destinations')).ap(Http.get('/events'));
    // Task("<div>some page with dest and events</div>")
    // $ :: String -> IO DOM
    const $ = selector => new IO(() => document.querySelector(selector));
    
    // getVal :: String -> IO String
    const getVal = compose(map(prop('value')), $);
    
    // signIn :: String -> String -> Bool -> User
    const signIn = curry((username, password, rememberMe) => { /* signing in */ });
    
    IO.of(signIn).ap(getVal('#email')).ap(getVal('#password')).ap(IO.of(false));
    // IO({ id: 3, email: 'gg@allin.com' })

    ----

    const R = require('ramda');
    
    class Container {
        static of(x) {
            return new Container(x);
        }
    
        constructor(x) {
            this.$value = x;
        }
    
        map (fn) {
            return Container.of(fn(this.$value));
        }
    
        ap (functor) {
            return functor.map(this.$value);
        }
    
        join() {
            return this.$value; 
        }
    
        chain(fn) {
            return this.map(fn).join();
        }
    
        inspect() {
            return `Container(${this.$value})`;
        }
    }
    
    class Maybe {
        get isNothing() {
          return this.$value === null || this.$value === undefined;
        }
      
        get isJust() {
          return !this.isNothing;
        }
      
        constructor(x) {
          this.$value = x;
        }
      
        inspect() {
          return this.isNothing ? 'Nothing' : `Just(${this.$value})`;
        }
      
        // ----- Pointed Maybe
        static of(x) {
          return new Maybe(x);
        }
      
        // ----- Functor Maybe
        map(fn) {
          return this.isNothing ? this : Maybe.of(fn(this.$value));
        }
      
        // ----- Applicative Maybe
        ap(f) {
          return this.isNothing ? this : f.map(this.$value);
        }
      
        // ----- Monad Maybe
        chain(fn) {
          return this.map(fn).join();
        }
      
        join() {
          return this.isNothing ? this : this.$value;
        }
      
        // ----- Traversable Maybe
        sequence(of) {
          this.traverse(of, identity);
        }
      
        traverse(of, fn) {
          return this.isNothing ? of(this) : fn(this.$value).map(Maybe.of);
        }
      }
    
      const add = a => b => a + b;
      const map = (fn, m) => m.map(fn);
      const notWorking = add(Container.of(2), Container.of(3));
      const containerOfAdd2 = map(add(3), Container.of(2));
      console.log(containerOfAdd2); // Contianer(5)
    
      const works = Container.of(2).chain(v => Container.of(3).map(add(v)));
      console.log(works); // Contianer(5)
    
      const ap = Container.of(2).map(add).ap(Container.of(3));
      console.log(ap)
    
      const ap2 = Container.of(add(2)).ap(Container.of(3));
      console.log(Maybe.of(add).ap(Maybe.of(2)).ap(Maybe.of(3)))
      console.log(Maybe.of(add(2)).ap(Maybe.of(3)))
    

      

  • 相关阅读:
    url 百分号解密
    16.UA池和代理池
    15.scrapy框架之日志等级、请求传参、提高scrapy框架的爬取效率
    14. scrip框架之5大核心组件和post请求
    13.scrapy 框架之递归解析(手动发送请求),
    12. scrapy 框架持续化存储
    11.scrapy框架简介和基础应用
    10. 移动端数据爬取
    09.python之网络爬虫之selenium、phantomJs和谷歌无头浏览器的自动化操作
    08 python之网络爬虫之乱码问题
  • 原文地址:https://www.cnblogs.com/Answer1215/p/10430481.html
Copyright © 2011-2022 走看看