Использование Either и немедленное возвращение ошибки
У меня есть функция, которая возвращает экземпляр Either, где левая сторона представляет исключение / ошибку, в то время как вторая сторона хранит возвращаемое значение.
Если экземпляр Either был создан для ветви Error, я хочу немедленно вернуться. Если экземпляр был создан правильно, я хочу обернуть его в "Возможно" и продолжить (так как он входит в функцию как "Может быть" и просматривается, только если это "Ничто").
Это работает в моих тестовых случаях:
- isN ничего не передается в:: поиск по ошибке
- ничего не передается в:: поиск успешно
- 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, но это другая проблема).
Я не понимаю, почему Правая сторона должна быть завернута в Либо, а Левая сторона - нет.