Skip to content

Commit 410f89d

Browse files
Maraclaude
andcommitted
🟢 recover, unwrap_or, unwrap_or_else: recovery carries the cost
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 27fac86 commit 410f89d

2 files changed

Lines changed: 35 additions & 1 deletion

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "terni"
3-
version = "0.1.0"
3+
version = "0.4.0"
44
edition = "2021"
55
license = "Apache-2.0"
66
description = "Ternary error handling: Success, Partial with measured loss, Failure. Because computation is not binary."

src/lib.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,40 @@ impl<T, E, L: Loss> Imperfect<T, E, L> {
221221
self.eh(f)
222222
}
223223

224+
/// Attempt recovery from Failure. The loss carries forward.
225+
///
226+
/// Success and Partial pass through unchanged.
227+
/// Failure → recovery function → result carries the failure's accumulated loss.
228+
///
229+
/// Recovery from Failure never produces Success — because the failure happened.
230+
/// The loss is real. The best you can do is recover a value and carry the cost.
231+
pub fn recover(self, f: impl FnOnce(E) -> Imperfect<T, E, L>) -> Imperfect<T, E, L> {
232+
match self {
233+
Imperfect::Success(v) => Imperfect::Success(v),
234+
Imperfect::Partial(v, l) => Imperfect::Partial(v, l),
235+
Imperfect::Failure(e, loss) => match f(e) {
236+
Imperfect::Success(v) => Imperfect::Partial(v, loss),
237+
Imperfect::Partial(v, l2) => Imperfect::Partial(v, loss.combine(l2)),
238+
Imperfect::Failure(e2, l2) => Imperfect::Failure(e2, loss.combine(l2)),
239+
},
240+
}
241+
}
242+
243+
/// Recover a default value from Failure. Always produces Partial.
244+
/// You can't un-fail. But you can get something back. The loss survives.
245+
pub fn unwrap_or_else(self, f: impl FnOnce(E) -> T) -> Imperfect<T, E, L> {
246+
match self {
247+
Imperfect::Success(v) => Imperfect::Success(v),
248+
Imperfect::Partial(v, l) => Imperfect::Partial(v, l),
249+
Imperfect::Failure(e, loss) => Imperfect::Partial(f(e), loss),
250+
}
251+
}
252+
253+
/// Recover with a static default. Always produces Partial on Failure.
254+
pub fn unwrap_or(self, default: T) -> Imperfect<T, E, L> {
255+
self.unwrap_or_else(|_| default)
256+
}
257+
224258
/// Propagate accumulated loss from `self` through `next`.
225259
///
226260
/// Deprecated in favor of [`eh`](Self::eh) / [`imp`](Self::imp) / [`tri`](Self::tri).

0 commit comments

Comments
 (0)