【问题标题】:Use of Either and returning the error immediately使用 Either 并立即返回错误
【发布时间】:2015-11-17 21:48:07
【问题描述】:

我有一个函数,它返回一个 Either 实例,其中左侧表示异常/错误,而第二侧存储返回值。

如果 Either 实例已被实例化到 Error 分支,我想立即返回。如果实例已被 Right 实例化,我想将其包装在 Maybe 中并继续(因为它作为 Maybe 进入函数,并且只有在它是 Nothing 时才会被查找)。

这是根据我的测试用例工作的:

  1. isNothing 传入 :: 查找错误
  2. isNothing 传入 :: 查找成功
  3. isJust(22) 被传入(不执行查找)

代码感觉还可以,但我不认为我可能缺少 Folktale data.either 库的一些细节。

// from data.monad
const someValue = Maybe.Nothing()

// ...snip...

if (someValue.isNothing) {

    // from data.either :: Either.Left | Either.Right
    const possiblySomeValue = yield lookupSomeValue()
    if(possiblySomeValue.isLeft) {
        return possiblySomeValue
    } else {
        someValue = Maybe.Just(possiblySomeValue.get())
    }
}

我正在将 ES6(Node 4.1)与 Folktale 结合起来:data.either 和 data.maybe。我的目标是提高我对如何以这种风格正确写作的理解


更新问题有点复杂,我背靠背独立查找,我觉得可以链接在一起:

// from data.monad
const someValue = Maybe.Nothing()

// ...snip...

if (someValue.isNothing) {

    // from data.either :: Either.Left | Either.Right
    const possiblySomeValue = yield lookupSomeValue()
    if(possiblySomeValue.isLeft) {
        return possiblySomeValue
    } else {
        someValue = Maybe.Just(possiblySomeValue.get())
    }
}

// from data.monad
const someValue2 = Maybe.Nothing()

// ...snip...

if (someValue2.isNothing) {

    // from data.either :: Either.Left | Either.Right
    const possiblySomeValue2 = yield lookupSomeValue2()
    if(possiblySomeValue2.isLeft) {
        return possiblySomeValue2
    } else {
        someValue2 = Maybe.Just(possiblySomeValue2.get())
    }
}

它的背靠背发生使代码超级丑陋...

【问题讨论】:

    标签: javascript monads maybe either folktale


    【解决方案1】:

    这是我认为更好的代码的当前状态。首先能够将 Maybe 转换为 any,以允许我使用转换链接 /orElse(Maybe.orElse 不允许采用函数,而 Either.orElse 确实采用转换函数)

    const maybeToEither = function(maybe) {
        if (maybe.isNothing) {
            return Either.Left(undefined)
        } else {
            return Either.Right(maybe.get())
        }
    }
    

    然后,由于我要将 Maybe.Just 解包到 Either.Right 作为转换的一部分,我只需要提供 orElse 转换。

    const someValue = maybeToEither(maybeSomeValue).orElse(function(ignore){
        return lookupSumValue()
    }).get()
    

    与我的实际问题相结合,生成器会导致一个稍微难看的解决方案。 lookupSomeValue 是一个生成器函数,所以我们需要 yield。此外,由于该值在多个地方使用,我们希望通过 get 将其强制转换为一个值。

    const someValue = (yield maybeToEither(maybeSomeValue).orElse(function(ignore){
        return lookupSumValue()
    })).get()
    

    所以当重复时,代码并不像我原来的解决方案那么糟糕 -

    const someValue = (yield maybeToEither(maybeSomeValue).orElse(function(ignore){
        return lookupSumValue()
    })).get()
    
    const someValue2 = (yield maybeToEither(maybeSomeValue2).orElse(function(ignore){
        const someRandom = getRandom()
        return lookupSumValue2(someRandom)
    })).get()
    

    我还在寻找更简洁的语法。如果我找到另一个解决方案,将更新。

    【讨论】:

      【解决方案2】:

      也许(完全是双关语)更好的方法

      const someValue = (yield maybeToEither(maybeSomeValue).cata({
          Left: lookupSumValue,
          Right: yieldableRight})).get()
      

      使用这两个辅助函数

      const yieldableRight = function(value){
          return function*(){ return Either.Right(value) }
      }
      
      const maybeToEither = function(maybe) {
          if (maybe.isNothing) {
              return Either.Left(undefined)
          } else {
              return Either.Right(maybe.get())
          }
      }
      

      lookupSomeValue 在表单中的位置(一个返回生成器的函数):

      const lookupSomeValue = function(){
          return ((function *(){
              return 10
          })())
      }
      

      问题是右侧需要返回一些可屈服的东西。出于某种原因,Koa/Co 在 Either.Right() 上窒息(即使对象是可屈服的),作为可屈服的——所以我返回了一个返回值的生成器。我明白了(我不明白为什么我不能屈服于 Either.Right,但这是一个不同的问题)。

      我不明白为什么右侧需要用 Either 包裹起来,而左侧则不需要。

      【讨论】:

        猜你喜欢
        • 2014-04-08
        • 1970-01-01
        • 2010-10-14
        • 2019-03-12
        • 1970-01-01
        • 1970-01-01
        • 2018-02-11
        • 2011-10-16
        • 2016-03-10
        相关资源
        最近更新 更多