函数式编程处理IF块

曾几何时,经常有人问我,“如果让你用函数式编程来实现X,该怎么做?”我比较喜欢这类的问题。我尽最大能力思考这类有趣的问题。本篇文章,我用一种更加函数式的方式来实现优雅处理IF函数块的问题。下面的代码有一个if块,但是没有else。

// A basic redux-thunk action that only dispatches when value exists
const someAction = value => dispatch => {
  const item = getItem(value)
  if (item != null) {
    dispatch({ type: 'ACTION', item })
  }
}

这里我们需要判断item有值的时候走dispatch方法,否则什么都不做。有一种思路是使用短路逻辑或者三元函数。

// short circuit
const someAction = value => dispatch => {
  const item = getItem(value)
  item && dispatch({ type: 'ACTION', item })
}

// ternary
const someAction = value => dispatch => {
  const item = getItem(value)
  item ? dispatch({ type: 'ACTION', item }) : null
}

短路逻辑和三元函数虽然都能解决这个问题,我们这里用另外一种思路。

Solution A: ifVal Helper Function

为了采用函数式的方法解决这个问题,我们先写个help类函数来实现,后面也更容易理解。

// 1: old school
function ifVal (x, f) {
  if (x == null) {
    return null
  } else {
    return f(x)
  }
}

// 2: convert to arrow function
const ifVal = (x, f) => {
  if (x == null) {
    return null
  } else {
    return f(x)
  }
}

// 3: convert if/else to a ternary operator
const ifVal = (x, f) => {
  return x == null ? null : f(x)
}

// 4: 简化写法
const ifVal = (x, f) => x == null ? null : f(x)

现在我们可以采用ifVal函数替代旧的if函数。

// functional alternative
const someAction = value => dispatch =>
  ifVal(getItem(value), item => dispatch({ type: 'ACTION', item }))

我们现在比较两种情况:

/**
 * execute the function if the value is not null or undefined
 * @param {Object} val - the value to test
 * @param {Function} fn - the function to execute.
 * @returns {Object} - null or the value of the executed function.
 */
const ifVal = (val, fn) => val == null ? null : fn(val)

// imperative example
const someAction = value => dispatch => {
  const item = getItem(value)
  if (item!= null) {
    dispatch({ type: 'ACTION', item })
  }
}

// functional example
const someAction = value => dispatch =>
  ifVal(getItem(value), item => dispatch({ type: 'ACTION', item }))

扩展阅读,可以参考下Ramda的whenunless, 和 ifelse  等其他函数。

Solution B: Functors

我们也可以使用MayBe Type,如果有值,返回Just type,否者就是Nothing type。我们使用Sanctuary 类库。

/*Examples of Sanctuary's Maybe*/

toMaybe(null) //=> Nothing
toMaybe(undefined) //=> Nothing
toMaybe(0) //=> Just(0)
toMaybe(false) //=> Just(false)
toMaybe(123) //=> Just(123)
toMaybe({ name: 'joel' }) //=> Just({ name: 'joel' })

MayBe Type是最简单的例子,这里之所以选择Maybe,是因为它完全兼容map数据。



请遵守《互联网环境法规》文明发言,欢迎讨论问题
扫码反馈

扫一扫,反馈当前页面

咨询反馈
扫码关注
返回顶部