Использование Either и немедленное возвращение ошибки

У меня есть функция, которая возвращает экземпляр Either, где левая сторона представляет исключение / ошибку, а вторая сторона хранит возвращаемое значение.

Если экземпляр Either был создан для ветви Error, я хочу немедленно вернуться. Если экземпляр был создан Right, я хочу обернуть его в Maybe и продолжить (поскольку он входит в функцию как Maybe и просматривается только в том случае, если это Nothing).

Это работает в моих тестовых примерах:

  1. isN ничего не передается в :: lookup является ошибкой
  2. isN ничего не передается в :: поиск успешен
  3. isJust (22) передается (поиск не выполняется)

Код выглядит нормально, но я не думаю, что мне может не хватать тонкостей данных Folktale в любой из библиотек.

// 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 (узел 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())
    }
}

Это сплошные события, которые делают код супер уродливым ...


person akaphenom    schedule 17.11.2015    source источник


Ответы (2)


Это текущее состояние моего кода, которое, я думаю, лучше. Сначала уметь преобразовать Maybe в любой, чтобы я мог связать / 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 - это функция-генератор, поэтому нам нужно уступить. Кроме того, поскольку значение используется в нескольких местах, мы хотим принудительно преобразовать его в значение с помощью 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()

Я все еще ищу более лаконичную грамматику. Обновлю с другим решением, если найду его.

person akaphenom    schedule 18.11.2015

Может быть (каламбур полностью задуман) лучший подход

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, а левую - нет.

person akaphenom    schedule 18.11.2015