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

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

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

Это работает в моих тестовых случаях:

  1. isN ничего не передается в:: поиск по ошибке
  2. ничего не передается в:: поиск успешно
  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())
    }
}

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

2 ответа

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

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

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

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 находится в форме (функция, которая возвращает Generator):

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

Проблема в том, что Правая сторона должна вернуть что-то, что является доходным. По какой-то причине Koa/Co душит Either.Right() (хотя Объекты являются доходными), как доходные - поэтому я возвращаю генератор, который возвращает значение. Я понимаю это (я не понимаю, почему я не могу уступить на Either.Right, но это другая проблема).

Я не понимаю, почему Правая сторона должна быть завернута в Либо, а Левая сторона - нет.

Другие вопросы по тегам