zoukankan      html  css  js  c++  java
  • [Functional Programming ADT] Adapt Redux Actions/Reducers for Use with the State ADT

    By using the State ADT to define how our application state transitions over time, we clear up the need for a some of the boilerplate that we typically need for a solid Redux integration. We can keep our action names and creators in the same file as the reducer they are used in, as we no longer need to have separate files to hand the same action across different portions of our state.

    We will build our a single reducer that will handle the integration with Redux and organize our State ADT based reducers in their own files and bring them into our main reducer to handle running our state transitions and the cases where we do not have an transition for a given action.

    // Action a :: {type: string, payload: a}
    // createAction :: String -> a -> Action a
    const createAction = type => payload => ({type, payload});
    const SELECT_CARD = 'SELECT_CARD';
    const selectCard = createAction(SELECT_CARD);
    
    
    // reducer :: (State, a) -> (State AppState ()) | Null
    const reducer = (prevState, {type, payload}) => {
        let result;
        switch(type) {
            case SELECT_CARD:
                result = feedback(payload);
                break;
            default: 
                result = null;   
        }
    
        return isSameType(State, result) ? result.execWith(prevState): prevState;
    }
    
    const sillyVerb = createAction('SILLY_VERB');
    
    console.log(
        reducer(
            state,
            selectCard('green-square')
        )
    )

    If we pass the right action, it will return the result, if a bad action, it keep the prev state untouched.

    ---

    const {prop, isSameType, State, omit, curry, converge,map, composeK, liftA2, equals, constant,option, chain, mapProps, find, propEq, isNumber, compose, safe} = require('crocks');
    const  {get, modify, of} = State; 
    
    const state = {
        cards: [
            {id: 'green-square', color: 'green', shape: 'square'},
            {id: 'orange-square', color: 'orange', shape: 'square'},
            {id: 'blue-triangle', color: 'blue', shape: 'triangle'}
        ],
        hint: {
            color: 'green',
            shape: 'square'
        },
        isCorrect: null,
        rank: 2
    }
    const inc = x => x + 1;
    const dec = x => x - 1;
    const incOrDec = b => b ? dec :  inc;
    const clamp = (min, max) => x => Math.min(Math.max(min, x), max);
    const clampAfter = curry((min, max, fn) => compose(clamp(min, max), fn))
    const limitRank = clampAfter(0, 4);
    const over = (key, fn) => modify(mapProps({[key]: fn}))
    const getState = key => get(prop(key));
    const liftState = fn => compose(
        of,
        fn
    )
    const getCard = id => getState('cards')
        .map(chain(find(propEq('id', id))))
        .map(option({}))
    const getHint = () => getState('hint')
        .map(option({}))
    const cardToHint = composeK(
        liftState(omit(['id'])),
        getCard
    )
    const validateAnswer = converge(
        liftA2(equals),
        cardToHint,
        getHint
    )
    const setIsCorrect = b => over('isCorrect', constant(b));
    const adjustRank = compose(limitRank, incOrDec);
    const updateRank = b => over('rank', adjustRank(b));
    const applyFeedback = converge(
        liftA2(constant),
        setIsCorrect,
        updateRank
    )
    const feedback = composeK(
        applyFeedback,
        validateAnswer
    )
    
    // Action a :: {type: string, payload: a}
    // createAction :: String -> a -> Action a
    const createAction = type => payload => ({type, payload});
    const SELECT_CARD = 'SELECT_CARD';
    const selectCard = createAction(SELECT_CARD);
    
    
    // reducer :: (State, a) -> (State AppState ()) | Null
    const reducer = (prevState, {type, payload}) => {
        let result;
        switch(type) {
            case SELECT_CARD:
                result = feedback(payload);
                break;
            default: 
                result = null;   
        }
    
        return isSameType(State, result) ? result.execWith(prevState): prevState;
    }
    
    const sillyVerb = createAction('SILLY_VERB');
    
    console.log(
        reducer(
            state,
            selectCard('green-square')
        )
    )
  • 相关阅读:
    Mapreduce实例-Top Key
    Mapreduce实例-分组排重(group by distinct)
    storm0.9.0.1升级安装
    mysql配置文件my.cnf详解
    MYSQL管理之主从同步管理
    一个经典实用的iptables shell脚本
    sed实例精解--例说sed完整版
    常用的主机监控Shell脚本
    Python(九)Tornado web 框架
    缓存、队列(Memcached、redis、RabbitMQ)
  • 原文地址:https://www.cnblogs.com/Answer1215/p/10346485.html
Copyright © 2011-2022 走看看