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')
        )
    )
  • 相关阅读:
    字符编码
    数据类型
    流程控制之判断,while循环,for循环
    数据类型,与用户交互,格式化输出,基本运算符
    操作系统,编程语言分类,执行python两种方式,变量,内存管理,定义变量的三个特征
    计算机硬件基础-笔记
    20200714_31adb命令和monkey压力稳定性测试
    20200707_28POM
    20200705_27DDT与Yaml数据驱动
    20200702_26UnitTest套件与运行器
  • 原文地址:https://www.cnblogs.com/Answer1215/p/10346485.html
Copyright © 2011-2022 走看看