zoukankan      html  css  js  c++  java
  • [Functional Programming] Using Last monoid with Maybe

    Imaging we have a deck of cards, eveytimes we need to pick one card from deck, the result we want to have is:

    // Selected: "A♠", 
    // Remaining: [ "2♠", "3♠", "4♠", "5♠", "6♠", "7♠", "8♠", "9♠", "10♠", "J♠", "Q♠", "K♠", "A♣", "2♣", "3♣", "4♣", "5♣", "6♣", "7♣", "8♣", "9♣", "10♣", "J♣", "Q♣", "K♣", "A♥", "2♥", "3♥", "4♥", "5♥", "6♥", "7♥", "8♥", "9♥", "10♥", "J♥", "Q♥", "K♥", "A♦", "2♦", "3♦", "4♦", "5♦", "6♦", "7♦", "8♦", "9♦", "10♦", "J♦", "Q♦", "K♦" ] '

    For selected, each time we want only one! remaining should be all the rest of cards which have been choosen. If we draw more than one time, remining cards should be reduced.

    For *Selected + remaining* pair, we can consider to use 'Pair' monad from ADT. Then our results looks like:

    // 'Pair( "A♠", [ "2♠", "3♠", "4♠", "5♠", "6♠", "7♠", "8♠", "9♠", "10♠", "J♠", "Q♠", "K♠", "A♣", "2♣", "3♣", "4♣", "5♣", "6♣", "7♣", "8♣", "9♣", "10♣", "J♣", "Q♣", "K♣", "A♥", "2♥", "3♥", "4♥", "5♥", "6♥", "7♥", "8♥", "9♥", "10♥", "J♥", "Q♥", "K♥", "A♦", "2♦", "3♦", "4♦", "5♦", "6♦", "7♦", "8♦", "9♦", "10♦", "J♦", "Q♦", "K♦" ] )'

    If chain drawCard a scond time, the results should be:

    // 'Pair( "2♠", [ "3♠", "4♠", "5♠", "6♠", "7♠", "8♠", "9♠", "10♠", "J♠", "Q♠", "K♠", "A♣", "2♣", "3♣", "4♣", "5♣", "6♣", "7♣", "8♣", "9♣", "10♣", "J♣", "Q♣", "K♣", "A♥", "2♥", "3♥", "4♥", "5♥", "6♥", "7♥", "8♥", "9♥", "10♥", "J♥", "Q♥", "K♥", "A♦", "2♦", "3♦", "4♦", "5♦", "6♦", "7♦", "8♦", "9♦", "10♦", "J♦", "Q♦", "K♦" ] )'

    Now we can pretty much know the Pair should be:

    // Deck :: Pair (Last Card) [Card]

    We use Last and Array tow semigourps, so the value know how to concat themselves, 'Last' will just keep the last value, Array will concat each other.

    We have deck.js file which provides data:

    const Last = require('crocks/Last');
    const Pair = require('crocks/Pair');
    
    const assign = require('crocks/helpers/assign');
    const chain = require('crocks/pointfree/chain');
    const liftA2 = require('crocks/helpers/liftA2');
    const map = require('crocks/pointfree/map');
    const reduce = require('crocks/pointfree/reduce')
    
    const suits = [
        { suit: '♠', color: 'dark' },
        { suit: '♣', color: 'dark' },
        { suit: '♥', color: 'light' },
        { suit: '♦', color: 'light' },
      ]
    
    const values = [
        { value: 1, face: 'A' },
        { value: 2, face: '2' },
        { value: 3, face: '3' },
        { value: 4, face: '4' },
        { value: 5, face: '5' },
        { value: 6, face: '6' },
        { value: 7, face: '7' },
        { value: 8, face: '8' },
        { value: 9, face: '9' },
        { value: 10, face: '10' },
        { value: 11, face: 'J' },
        { value: 12, face: 'Q' },
        { value: 13, face: 'K' },
      ];
    
    // Deck :: Pair (Last Card) [Card]  
    // deck :: Deck
    const deck = Pair(Last.empty(), liftA2(assign, suits, values));
    // displayCard :: Card -> String
    const displayCard = ({face, suit}) =>
      `${face}${suit}`;
    // displayCards :: [Card] -> [String]
    const displayCards = map(displayCard);
    
    // pickCard : [ Card ] -> Pair [Card][Card]
    const pickCard = cs => {
      const idx = Math.floor(Math.random() * cs.length);
    
      return Pair(
          [].concat(cs[idx]),
          cs.slice(0, idx).concat(cs.slice(idx + 1))
      )
    }
    // shuffleCards : [ Cards ] -> [ Cards ]
    const shuffleCards = cards => reduce(
      chain(pickCard), Pair([], cards), cards
    ).fst();
    
    module.exports = {
        deck,
        displayCard,
        displayCards,
        pickCard,
        shuffleCards
    }
    

    Important here, is to know how we define our 'deck' to Pair monad with Last and Array.

    // Deck :: Pair (Last Card) [Card]  
    // deck :: Deck
    const deck = Pair(Last.empty(), liftA2(assign, suits, values));

    For our consumer part, we can do:

    const log = require('./lib/log');
    const Last = require('crocks/Last');
    const Pair = require('crocks/Pair');
    
    const bimap = require('crocks/pointfree/bimap');
    
    const {deck, displayCard, displayCards} = require('./model/deck');
    
    const look = bimap(
        x => displayCard(x.option('')), 
        displayCards
    );
    
    // Deck :: Pair (Last Card) [Card]
    // drawCard : Int -> [Card] -> Deck
    const drawCard = indx => deck => {
        return Pair(
            Last(deck[indx]),
            deck.slice(0, indx).concat(deck.slice(indx + 1))
        )
    }
    
    const m = deck
        .chain(drawCard(0))
        .chain(drawCard(0))
        .chain(drawCard(0))
        .chain(drawCard(0));
    
    log(
        look(m)
    );
    // 'Pair( "4♠", [ "5♠", "6♠", "7♠", "8♠", "9♠", "10♠", "J♠", "Q♠", "K♠", "A♣", "2♣", "3♣", "4♣", "5♣", "6♣", "7♣", "8♣", "9♣", "10♣", "J♣", "Q♣", "K♣", "A♥", "2♥", "3♥", "4♥", "5♥", "6♥", "7♥", "8♥", "9♥", "10♥", "J♥", "Q♥", "K♥", "A♦", "2♦", "3♦", "4♦", "5♦", "6♦", "7♦", "8♦", "9♦", "10♦", "J♦", "Q♦", "K♦" ] )'

    Thre is one problem: 

    if we change last chain call to:

    const m = deck
        .chain(drawCard(0))
        .chain(drawCard(0))
        .chain(drawCard(0))
        .chain(drawCard(99));

    Our code throw error:

    TypeError: Cannot match against 'undefined' or 'null'.

    This is because, index 99 is out or range;

    Last(deck[indx]),

    Because Last can take a single value or a Maybe type, and return when value is present and wrap with Just, or return Nothing, which means we can prevent this error happens by add Maybe:

    const safe = require('crocks/Maybe/safe');
    const isDefined = require('crocks/predicates/isDefined');
    
    // isValid :: a -> Maybe a
    const isValid = safe(isDefined);
    
    // Deck :: Pair (Last Card) [Card]
    // drawCard : Int -> [Card] -> Deck
    const drawCard = indx => deck => {
        return Pair(
            // Last can take Maybe or value in arguement, 
            // make it possible to control the code safety
            Last(isValid(deck[indx])),
            deck.slice(0, indx).concat(deck.slice(indx + 1))
        )
    }

    Now if we still try to get 99 index, it will just ignore it:

    const m = deck
        .chain(drawCard(0))
        .chain(drawCard(0))
        .chain(drawCard(0))
        .chain(drawCard(99));
    
    log(
        look(m)
    );
    //'Pair( "3♠", [ "4♠", "5♠", "6♠", "7♠", "8♠", "9♠", "10♠", "J♠", "Q♠", "K♠", "A♣", "2♣", "3♣", "4♣", "5♣", "6♣", "7♣", "8♣", "9♣", "10♣", "J♣", "Q♣", "K♣", "A♥", "2♥", "3♥", "4♥", "5♥", "6♥", "7♥", "8♥", "9♥", "10♥", "J♥", "Q♥", "K♥", "A♦", "2♦", "3♦", "4♦", "5♦", "6♦", "7♦", "8♦", "9♦", "10♦", "J♦", "Q♦", "K♦" ] )'

    ---

    Full code index.jks:

    const log = require('./lib/log');
    const Last = require('crocks/Last');
    const Pair = require('crocks/Pair');
    
    const bimap = require('crocks/pointfree/bimap');
    const safe = require('crocks/Maybe/safe');
    const isDefined = require('crocks/predicates/isDefined');
    
    const {deck, displayCard, displayCards} = require('./model/deck');
    
    const look = bimap(
        x => displayCard(x.option('')), 
        displayCards
    );
    
    // isValid :: a -> Maybe a
    const isValid = safe(isDefined);
    
    // Deck :: Pair (Last Card) [Card]
    // drawCard : Int -> [Card] -> Deck
    const drawCard = indx => deck => {
        return Pair(
            // Last can take Maybe or value in arguement, 
            // make it possible to control the code safety
            Last(isValid(deck[indx])),
            deck.slice(0, indx).concat(deck.slice(indx + 1))
        )
    }
    
    const m = deck
        .chain(drawCard(0))
        .chain(drawCard(0))
        .chain(drawCard(0))
        .chain(drawCard(99));
    
    log(
        look(m)
    );

      

  • 相关阅读:
    SNMP++
    临界区,互斥量,信号量,事件的区别
    2015 年最棒的 5 个 HTML5 框架(转)
    java.lang.OutOfMemoryError: PermGen space及其解决方法
    java.net.SocketException: Unrecognized Windows Sockets error: 0: JVM_Bind
    eclipse安装tomcat插件
    (转)Activity的跳转与传值
    Android SDK下载和更新失败的解决方法
    Android客户端WebView控件与Javascript交互
    SCI期刊
  • 原文地址:https://www.cnblogs.com/Answer1215/p/10609818.html
Copyright © 2011-2022 走看看