Reference
Core types
Bases: Generic[T]
Holds a successfully computed / present value.
Methods mirror those on _Nothing
, but actually apply the provided
transformations. Failures during mapping or binding gracefully degrade
to Nothing
.
Parameters
value : T The wrapped payload.
Truthiness
Evaluates to True in boolean context:
>>> bool(just(0))
True
Transformations
fmap(fn): Apply a pure function, catching exceptions -> Maybe bind(fn): Chain a Maybe-returning function, validating return type
Source code in src/talvez/core.py
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 |
|
is_just
property
Return True (this is a Just).
is_nothing
property
Return False (this is a Just).
bind(fn)
Chain a function returning another Maybe (monadic bind).
Enforces that fn
returns either a Just
or Nothing
; any
other return type results in Nothing
.
Parameters
fn : Callable[[T], Maybe[U]] Function returning a Maybe.
Returns
Maybe[U]
Result of fn(self.value)
or Nothing on error / type mismatch.
Raises
(internally caught)
Any exception from fn
results in Nothing.
Source code in src/talvez/core.py
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
|
fmap(fn)
Apply a pure function to the contained value.
Exceptions raised by fn
cause the result to become Nothing
.
Parameters
fn : Callable[[T], U] Pure transformation function.
Returns
Maybe[U] Just of transformed value, or Nothing on exception.
Source code in src/talvez/core.py
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
|
get_or(default)
Return the wrapped value (ignoring the default).
Provided for API symmetry with _Nothing.get_or
.
Parameters
default : U (Unused) placeholder for symmetry.
Returns
T The contained value.
Source code in src/talvez/core.py
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
|
to_optional()
Convert to a standard Optional (always the underlying value here).
Returns
Optional[T] The contained value (never None unless it was explicitly None).
Source code in src/talvez/core.py
250 251 252 253 254 255 256 257 258 259 |
|
Wrap a raw value into a Just
.
Parameters
a : T Value to wrap.
Returns
Just[T] A Maybe representing presence.
Source code in src/talvez/core.py
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
|
Obtain the Nothing
sentinel.
Returns
_Nothing The shared singleton representing absence.
Source code in src/talvez/core.py
297 298 299 300 301 302 303 304 305 306 |
|
Convert a standard Optional into a Maybe.
Parameters
opt : Optional[T] An optional value (None indicates absence).
Returns
Maybe[T]
Just(opt)
if not None, else Nothing
.
Source code in src/talvez/core.py
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
|
Turn an iterator of Maybe values into a Maybe of a list.
Short-circuits to Nothing
if any element is Nothing
; otherwise
collects unwrapped values into a list.
Parameters
maybes : Iterator[Maybe[T]] Iterator yielding Maybe values.
Returns
Maybe[list[T]] Just of collected values if all succeed, else Nothing.
Examples
>>> sequence(iter([just(1), just(2)])).get_or([])
[1, 2]
>>> sequence(iter([just(1), nothing(), just(3)])).is_nothing
True
Source code in src/talvez/core.py
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 |
|
Decorators
Decorator factory: wrap a function so it returns a Maybe (Just / Nothing).
The wrapped function is executed inside a protective layer that
- Captures exceptions -> returns
Nothing
- Optionally treats warnings as failures (
allow_warning=False
) - Applies an
ensure
predicate to the result; non-True ->Nothing
- Returns
Just(result)
on success
IMPORTANT: The ensure
predicate must return the literal boolean True
for acceptance. Returning any other truthy object (e.g., 1, non-empty list)
will be considered failure because talvez.predicates.not_true
checks for
identity with True
. This enforces discipline and avoids accidental
truthiness bugs.
Parameters
ensure : Optional[Callable[[Any], bool]], default=None
Predicate applied to the successful raw result. If omitted, all results
are accepted. If the predicate raises an exception or returns anything
other than the literal True
, the outcome becomes Nothing
.
allow_warning : bool, default=False
If False, any warning raised during execution causes the decorator to
return Nothing
. If True, warnings are ignored.
Returns
Callable[[Callable[..., T]], Callable[..., Maybe[T]]]
A decorator that transforms a function returning T into one returning
Maybe[T]
.
Examples
>>> from talvez import just, nothing
>>> @maybe()
... def parse_int(s: str) -> int:
... return int(s)
...
>>> parse_int("10").get_or(None)
10
>>> parse_int("x").is_nothing
True
With an ensure predicate:
>>> @maybe(ensure=lambda v: v > 0)
... def delta(x): return x - 1
...
>>> delta(5).is_just
True
>>> delta(0).is_nothing # ensure failed (returns -1)
True
Handling warnings:
>>> import warnings
>>> @maybe(allow_warning=False)
... def risky():
... warnings.warn("deprecated")
... return 42
...
>>> risky().is_nothing
True
>>> @maybe(allow_warning=True)
... def tolerant():
... warnings.warn("deprecated")
... return 42
...
>>> tolerant().get_or(None)
42
Edge Cases
- Exception in function: returns
Nothing
- Exception in ensure predicate: returns
Nothing
- Warning + allow_warning=False: returns
Nothing
- Function returns None and ensure not provided: wraps as Just(None) (use ensure to reject None if undesired).
Source code in src/talvez/wrappers.py
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
|
Decorator factory: wrap a function so it returns a raw value with fallback.
Unlike maybe
, this returns the successful result directly, or a
user-specified default
on failure. Failure conditions mirror maybe
:
- Exception raised
- Warning emitted (if allow_warning=False
)
- Ensure predicate not returning literal True
- Ensure predicate raising an exception
Parameters
default : Any
The value returned when the wrapped function "fails". Should be a
sensible sentinel consistent with your domain.
ensure : Optional[Callable[[Any], bool]], default=None
Predicate validating the raw result. Must return the literal True to
accept; any other outcome triggers the fallback.
allow_warning : bool, default=False
If False, any warning turns the result into default
. If True, warnings
are ignored.
Returns
Callable[[Callable[..., T]], Callable[..., Any]] A decorator that converts a function returning T into one returning T-or-default.
Examples
>>> @perhaps(default=0)
... def safe_div(a, b): return a / b
...
>>> safe_div(10, 2)
5.0
>>> safe_div(10, 0)
0
With ensure:
>>> @perhaps(default=None, ensure=lambda v: v > 10)
... def compute(x): return x * 3
...
>>> compute(5)
15
>>> compute(3) # 3*3 = 9 -> ensure fails
None
Warning handling:
>>> import warnings
>>> @perhaps(default=-1, allow_warning=False)
... def noisy():
... warnings.warn("careful")
... return 99
...
>>> noisy()
-1
Design Rationale
Use perhaps
when you want ergonomic fallback semantics without having to
manipulate a Maybe object explicitly, for contexts where sentinel defaults
are acceptable and clearly documented.
Edge Cases
- If the function legitimately returns a value equal to
default
, you cannot distinguish fallback vs success—choose a unique sentinel if needed. - As with
maybe
, ensure must return literal True (not just truthy).
Source code in src/talvez/wrappers.py
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
|
ensure predicate behavior
The ensure
callable MUST return the literal boolean True
(not just a truthy value) for a result to be accepted. Anything else (False, 1, [], object()) is treated as failure. This is enforced via the not_true
predicate for defensive programming.
Choosing between maybe() and perhaps()
- Use
@maybe()
when you want explicitJust
/Nothing
handling. - Use
@perhaps(default=...)
when a sentinel fallback is more ergonomic.
Composition and chaining
Sequentially apply a series of Maybe-producing functions, short-circuiting on the first failure.
This function implements a left-to-right monadic bind chain. It starts with an
initial Maybe m
and applies each function in fns
to the unwrapped value
of the current Just
(via bind
). If at any point the current value is
Nothing
, evaluation stops early and Nothing
is returned.
Parameters
m : Maybe[Any]
The initial Maybe value (typically just(x)
or nothing()
).
*fns : Callable[[Any], Maybe[Any]]
A variadic sequence of functions. Each function must accept the unwrapped
value from the previous Just
and return a new Maybe
.
Returns
Maybe[Any]
The resulting Maybe after applying all functions, or the first Nothing
encountered.
Notes
- This is analogous to a fold/ reduce over monadic bind operations.
- Functions are only invoked if the current accumulator is a
Just
. - Any function returning
Nothing
halts further processing.
Examples
>>> from talvez import just, nothing
>>> def parse_int(s: str):
... try:
... return just(int(s))
... except ValueError:
... return nothing()
...
>>> def reciprocal(x: int):
... return nothing() if x == 0 else just(1 / x)
...
>>> chain(just("10"), parse_int, reciprocal).get_or(None)
0.1
>>> chain(just("foo"), parse_int, reciprocal).is_nothing
True
Edge Cases
- Passing no functions: returns the original
m
. - If
m
is alreadyNothing
, no functions are executed.
Source code in src/talvez/ops.py
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
|
Compose multiple Maybe-producing functions into a reusable pipeline.
Returns a new function that expects an initial Maybe
and applies the
provided functions in order using chain
. This is useful when you want to
define a processing pipeline once and reuse it across different starting
values.
Parameters
*fns : Callable[[Any], Maybe[Any]]
A sequence of functions, each taking a plain (unwrapped) value and
returning a Maybe
.
Returns
Callable[[Maybe[Any]], Maybe[Any]]
A function that, given an initial Maybe
, applies the pipeline.
Examples
>>> from talvez import just, nothing
>>> def non_empty(s: str):
... return just(s) if s else nothing()
...
>>> def to_int(s: str):
... try:
... return just(int(s))
... except ValueError:
... return nothing()
...
>>> def positive(x: int):
... return just(x) if x > 0 else nothing()
...
>>> pipeline = compose_maybe(non_empty, to_int, positive)
>>> pipeline(just("42")).get_or(None)
42
>>> pipeline(just("")).is_nothing
True
>>> pipeline(just("-5")).is_nothing
True
Comparison
This: pipeline = compose_maybe(f1, f2, f3) result = pipeline(just(x)) Is equivalent to: result = chain(just(x), f1, f2, f3)
Edge Cases
- If no functions are provided, the returned runner is the identity on
Maybe
. - Fail-fast semantics are inherited from
chain
.
Source code in src/talvez/ops.py
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
|
Predicates
Return True if the argument is NOT the literal boolean True.
This helper is intentionally strict: it only treats the single object True
as true-ish for the negation test. Any other truthy value (e.g., 1, "yes",
non‑empty containers) returns True because it is not the singleton True
.
Parameters
x : Any
Value to test for identity with the boolean True
.
Returns
bool
False only when x is True
; True otherwise.
Examples
>>> not_true(True)
False
>>> not_true(False)
True
>>> not_true(1)
True
>>> not_true("anything")
True
Notes
This function is used internally to implement other predicates without
conflating general truthiness with strict identity to True
.
Source code in src/talvez/predicates.py
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
|
Return True if the value is not None.
Parameters
a : Any Value to check.
Returns
bool
True if a is not None
, False otherwise.
Examples
>>> not_null(None)
False
>>> not_null(0)
True
>>> not_null("")
True
Source code in src/talvez/predicates.py
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
|
Return True if the value is NOT a floating-point NaN (Not-a-Number).
Parameters
a : Any Value to check. Only floats are considered; other types return True.
Returns
bool
False only when a
is a float and math.isnan(a)
is True.
Examples
>>> not_nan(float("nan"))
False
>>> not_nan(3.14)
True
>>> not_nan("nan")
True
Source code in src/talvez/predicates.py
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
|
Return True if the value is not positive or negative infinity.
Parameters
a : Any Value to check. Only ints/floats are considered for +/- infinity.
Returns
bool
False when a
is +inf or -inf (as a numeric); True otherwise.
Examples
>>> not_infinite(float("inf"))
False
>>> not_infinite(float("-inf"))
False
>>> not_infinite(42)
True
>>> not_infinite("inf")
True
Source code in src/talvez/predicates.py
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
|
Composite predicate: value is neither None, NaN, nor infinite.
This is a convenience aggregator combining
- not_null
- not_nan
- not_infinite
Parameters
a : Any Value to test.
Returns
bool True only if all component predicates pass.
Examples
>>> not_undefined(None)
False
>>> not_undefined(float("nan"))
False
>>> not_undefined(float("inf"))
False
>>> not_undefined(0)
True
Source code in src/talvez/predicates.py
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
|
Return True if the object has a length > 0, or if it has no length concept.
Semantics
- If the object implements len, returns len(a) > 0.
- If it does not (AttributeError / TypeError), treats it as "not empty" and returns True (optimistic / permissive behavior).
Parameters
a : Any Value or container to check.
Returns
bool False only when a length can be determined AND that length is 0.
Examples
>>> not_empty([])
False
>>> not_empty([1])
True
>>> not_empty("")
False
>>> not_empty("hi")
True
>>> class NoLen: pass
>>> not_empty(NoLen())
True # no length concept -> considered not empty
Notes
Choosing to treat objects without a length as "not empty" avoids false negatives on scalar values; adjust if your domain requires stricter checks.
Source code in src/talvez/predicates.py
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
|
Logical combinators
Logical AND combinator for predicates.
Returns a new predicate that evaluates each provided predicate in order. Short-circuits and returns False on the first predicate that does NOT strictly return the boolean True (identity check). Any truthy non-True value (e.g. 1) is considered a failure, enforcing discipline in predicate implementations.
Parameters
*preds : Predicate Predicates of signature (Any) -> bool.
Returns
Predicate Composite predicate representing logical conjunction.
Examples
>>> p = and_(not_null, not_nan, not_infinite)
>>> p(10)
True
>>> p(float("nan"))
False
>>> p(None)
False
Edge Cases
- No predicates: returns a predicate that always returns True.
Source code in src/talvez/predicates.py
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
|
Logical OR combinator for predicates.
Returns a predicate that evaluates each provided predicate in order and short-circuits on the first that returns the literal True. Exceptions inside individual predicates are swallowed (treated as a non-match) to keep the OR robust.
Parameters
*preds : Predicate Predicates of signature (Any) -> bool.
Returns
Predicate Composite predicate representing logical disjunction.
Examples
>>> p = or_(not_null, not_empty)
>>> p(None)
False # both fail
>>> p("")
False # not_null OK but empty string -> not_empty False
>>> p("x")
True
>>> p([]) # not_null True but empty -> not_empty False -> overall False
False
Edge Cases
- No predicates: returns a predicate that always returns False.
- Non-boolean truthy values returned by individual predicates are ignored unless they are exactly True, encouraging explicit boolean returns.
Source code in src/talvez/predicates.py
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 |
|
Tip
These are strict: each predicate must return the literal True
to be considered a pass. Any other truthy value will fail the conjunction (and_
) or be ignored in the disjunction (or_
).
Common usage patterns
from talvez import maybe, just, nothing, chain, compose_maybe, not_null, and_
@maybe(ensure=lambda x: x > 0)
def positive_delta(x: int) -> int:
return x - 1
pipeline = compose_maybe(
lambda x: just(x * 2),
lambda y: positive_delta(y) # returns Maybe[int]
)
result = pipeline(just(10)) # Just(19)
failed = pipeline(just(0)) # Nothing
Error & warning handling
-
maybe(..., allow_warning=False)
turns any emitted warning into failure. -
perhaps(..., allow_warning=True)
will ignore warnings and still return the raw value.
Interoperability
Purpose | Helper |
---|---|
Convert Optional[T] to Maybe[T] | from_optional |
Convert Maybe[T] to Optional[T] | maybe_val.to_optional() |
Batch short-circuit across many Maybes | sequence(iter_of_maybes) |