zoukankan      html  css  js  c++  java
  • [Functional Programming] Rewrite a reducer with functional state ADT

    For example we have a feature reducer like this:

    // selectCard :: String -> Action String
    export const selectCard =
      createAction(SELECT_CARD)
    
    // showFeedback :: String -> Action String
    export const showFeedback =
      createAction(SHOW_FEEDBACK)
    
    // reducer :: Action a -> (State AppState ()) | Null
    const reducer = ({ type, payload }) => {
      switch (type) {
        case SELECT_CARD:
          return answer(payload)
    
        case SHOW_FEEDBACK:
          return feedback(payload)
      }
    
      return null
    }
    
    export default reducer

    First of all, we can replace 'swtich' statement with normal Object:

    const actionReducer = {
      SELECT_CARD: answer,
      SHOW_FEEDBACK: feedback
    }  
    
    // reducer :: Action a -> (State AppState ()) | Null
    const reducer = ({ type, payload }) => (actionReducer[type] || Function.prototype)(payload)
    

    In case of ´actionReducer[type]´ return undefined, we default a function by `Function.prototype`, ready to take a payload.

    const reducer = ({ type, payload }) => (actionReducer[type] || Function.prototype)(payload)

    This type of code is suitable for using 'Maybe'.

    // createReducer :: ActionReducer -> Reducer
    export const createReducer = actionReducer =>
      ({ type, payload }) =>
        prop(type, actionReducer)
          .map(applyTo(payload))

    Refactor:

    // showFeedback :: String -> Action String 
    export const showFeedback =
      createAction(SHOW_FEEDBACK)
    
    const reducer = createReducer({
      SELECT_CARD: answer,
      SHOW_FEEDBACK: feedback
    })
    
    // reducer :: Action a -> (State AppState ()) | Null
    // const reducer = ({ type, payload }) => 
    //   (actionReducer[type] || Function.prototype)(payload)
    
    export default reducer

    For this workflow, the following code should also be chagned to handle Maybe type:

    // From
    import turn from './turn'
    
    //reducer :: (AppState, Action a) -> AppState
    const reducer = (prev, action) =>
      const result = turn(action)
    
      return isSameType(State, result)
        ? result.execWith(prev)
        : prev
    }
    
    export default reducer 
    
    // To
    import turn from './turn'
    
    //reducer :: (AppState, Action a) -> AppState
    const reducer = (prev, action) =>
      turn(action)
        .chain(safe(isSameType(State)))
    //   ? result.execWith(prev)
    // : prev export default reducer

    Here ´turn(action)´ return a Maybe type, we still need to check whether inside Maybe, it is `State` type, 

    .chain(safe(isSameType(State)))

    If it is, then we call `execWith` otherwise we return previous state:

    const reducer = (prev, action) =>
     turn(action)
       .chain(safe(isSameType(State)))
       .map(execWith(prev))
       .option(prev)
  • 相关阅读:
    092、部署Graylog日志系统(2019-05-16 周四)
    091、万能的数据收集器 Fluentd (2019-05-15 周三)
    090、ELK完成部署和使用 (2019-05-13 周二)
    在CentOS7上无人值守安装Zabbix4.2
    089、初探ELK (2019-05-13 周一)
    34、Scrapy 知识总结
    33、豆瓣图书短评
    32、出任爬虫公司CEO(爬取职友网招聘信息)
    31、当当图书榜单爬虫
    30、吃什么不会胖
  • 原文地址:https://www.cnblogs.com/Answer1215/p/11436596.html
Copyright © 2011-2022 走看看