either 빌더 & Raise 스코프
블록을 Raise<E> 스코프 안에서 실행합니다: 타입 있는
에러로 단락할 수 있는 일직선 코드입니다. raise된 E는
Left가 되고, 정상 반환은 Right가 됩니다.
강의
빌더는 여러분의 블록에 스코프 r을 건네줍니다 — Kotlin
Arrow의 either { }를 이식한 것입니다. 모든 것이
여기에 달려 있습니다. r.을 입력하면 어휘 전체를 발견할 수
있습니다:
r.bind(either)/r.bindAll(eithers)— 성공 값을 풀어내거나, 실패와 함께 단락합니다.r.ensure(cond, () => err)— 타입 있는 에러 버전의require.r.ensureNotNull(x, () => err)— non-null을 반환하며, 타입 승격이 일어납니다.r.recover(block, onRaise)— 중첩 스코프에서 raise된 에러를 처리하고 계속 진행합니다.r.withError(transform, block)— 다른 에러 타입을 이 스코프에 맞게 변환합니다.r.raise(err)— 곧바로 단락합니다.Never를 반환하므로 실행이 거기서 멈춘다는 사실을 흐름 분석도 알고 있습니다.
내부 구현은 결코 flatMap 연쇄가 아닙니다. 실패한
bind는 스코프 토큰이 달린 비공개 신호를 던지고, 빌더가
자신의 경계에서 그것을 잡아냅니다. 그래서 이른 반환, 반복문,
if가 블록 안에서 전부 그대로 동작하고, 중첩된 빌더가 서로의
에러를 가로채는 일도 없습니다. eitherAsync는 비동기
쌍둥이입니다 — 어휘는 같고 await도 쓸 수 있습니다(raise는
같은 await 체인 안에서만).
데모 1 · ensure & ensureNotNull
데모 2 · bind — flatMap 피라미드를 끝내는 무기
데모 3 · recover, withError & raise
데모 4 · eitherCatching — 예외 경계를 미리 결합한 빌더
실제 파싱은 두 갈래로 동시에 실패합니다. 우리가 정한 규칙은 타입 있는
오류를 raise하고, 플랫폼(int.parse,
jsonDecode)은 throw합니다.
eitherCatching은 either +
catching을 하나로 합친 빌더입니다 — 블록은 raise하거나
throw할 수 있고, 두 번째 인자가 던져진 예외를 같은 타입의 오류로
변환합니다. raise 시그널 자체는 절대 여기에 전달되지 않습니다.
recover도 같은 선택적 onThrow: 절을 받아
Arrow 2.x의 3절짜리 recover(block, recover, catch)를
완성합니다.
직접 해 보기
연습: checkAge가 예외를 던지는 대신 타입 있는 에러로
실패하도록 만들어 보세요 — 파싱에는 ensureNotNull을, 나이
제한에는 ensure를 쓰면 됩니다.
toList()로 구체화하거나
즉시 실행 Either 종결 연산자를
사용하세요. 지연된 raise는 RaiseLeakedError로 요란하게
실패합니다. (2) raise 블록 안에서 맨몸 catch를 쓰지
마세요 — 단락 신호를 항상 통과시키는
catching/catchingAsync를 사용하세요.