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)
  • 相关阅读:
    Android开发中适配多种 ROM 的快捷方式是如何实现的?
    Android开发利用Volley框架下载和缓存网络图片
    Android调用系统相机、自定义相机、处理大图片
    Excel中MATCH函数的正确使用
    Excel中INDEX函数的使用
    (转)Delphi2009初体验
    利用NSA的MS17-010漏洞利用工具实现Win 7和Win Server 2008系统入侵
    delphi 的结构体对齐关键字
    KVM虚拟化(一)—— 介绍与简单使用
    kvm虚拟化学习笔记(四)之kvm虚拟机日常管理与配置
  • 原文地址:https://www.cnblogs.com/Answer1215/p/11436596.html
Copyright © 2011-2022 走看看