Maybe.jl
Tutorial is the best place to start.
Maybe
Maybe
— ModuleMaybe.jl: Optional value handling for Julia
Maybe.jl provides functions and macros for handling the values of type Union{Some,Nothing}
; i.e., option type. The main entry point for the optional value handling is the macro @?
:
julia> using Maybe
julia> data = [1, 3, 2, 1];
julia> @? data[findfirst(iseven, data)]
Some(2)
julia> y = @? data[findfirst(>=(4), data)]
julia> @assert y === nothing
Maybe.jl also provides low-level functions such as Maybe.get
which is the "Maybe" variant of Base.get
:
julia> Maybe.get(Dict(:a => 1), :a)
Some(1)
julia> @assert Maybe.get(Dict(:a => 1), :b) === nothing
See more in the documentation.
Maybe.T
— ConstantMaybe.T{T}
A shorthand for Union{Some{T},Nothing}
.
Maybe.@?
— Macro@? expr
@? :debug expr
"Lift" functions to operate on Union{Some{T}, Nothing}
.
Idea:
- Each function
f(::T₁, ..., ::Tₙ) -> ::R
is (conceptually) lifted tof′(::Union{Some{T₁}, Nothing}, ..., ::Union{Some{Tₙ}, Nothing}) -> ::Union{Some{R}, R, Nothing}
. - If any of the returned value is
nothing
, the evaluation ofexpr
in@?
short-circuits and evaluates tonothing
.
Debugging support (experimental): In the two-argument form @? :debug expr
(:debug
is the literal symbol :debug
), @?
inserts @debug
logging statements for all possible short-circuiting points. This logging statement prints the expression that is evaluated to nothing
and all the local variables using Base.@locals
. This macro also inserts a call to a no-op function Maybe._break
. When using Debugger.jl, the state just before exit can be examined by adding it to the breakpoint with bp add Maybe._break
.
See the tutorial for more information.
Examples
julia> using Maybe
julia> dict = Dict(:a => Dict(:b => 1));
julia> @? dict[:a][:b] + 2
Some(3)
julia> @? dict[:a][:b] + dict[:c] # => nothing
The expression in @?
short-circuits when a call returns nothing
:
julia> f() = nothing;
julia> @? println(f())
Some
is unwrapped when it appears in the argument position:
julia> f() = Some("hello");
julia> @? println(f())
hello
Non-nothing
returned value is always ensured to be wrapped in Some
at the end
julia> f() = "hello";
julia> @? f()
Some("hello")
julia> g() = Some("hello");
julia> @? g()
Some("hello")
nothing
literal is always wrapped
julia> @? Some(nothing)
Some(nothing)
return $expr
does not return when $expr
evaluates to nothing
julia> f() = (@? return identity(nothing); return 1);
julia> f()
1
return $expr
returns Some($expr)
:
julia> @? 1 + 1
Some(2)
julia> f() = @? return 1 + 1;
julia> f()
Some(2)
$(...)
can be used for switching to the normal evaluation
julia> @? Some(Some(Some(1)))
Some(1)
julia> @? $(Some(Some(Some(1))))
Some(Some(Some(Some(1))))
$f(...)
can be used for extra wrapping with Some
julia> f() = Some("hello");
julia> @? f()
Some("hello")
julia> @? $f()
Some(Some("hello"))
@?
recursively transforms functions
julia> @? f(dict, i, j, k) =
get(dict, i) do
dict[j] + dict[k]
end;
julia> f(Dict(), :a, :b, :c)
julia> f(Dict(:a => 1), :a, :b, :c)
Some(1)
julia> f(Dict(:b => 1), :a, :b, :c)
julia> f(Dict(:b => 1, :c => 2), :a, :b, :c)
Some(3)
Maybe.@something
— Macro@something(ex₁, ex₂, ..., exₙ)
@something{ex₁; ex₂; ...; exₙ}
@something {ex₁; ex₂; ...; exₙ}
A lazy version of something(x₁, x₂, ..., xₙ)
. Evaluate exᵢ
one by one and return something(result)
of the first non-nothing
result
of exᵢ
. Throw an error if everything is evaluated to nothing
.
@something{ex₁; ex₂; ...; exₙ}
requires Juila >= 1.5.
Examples
julia> using Maybe: @something
julia> @something(
(println("first"); nothing),
(println("second"); 2),
(println("third"); 3),
)
first
second
2
julia> function maybe_add(xs)
a = @something(get(xs, 1, nothing), return)
b = @something(get(xs, 2, nothing), return)
return a + b
end;
julia> maybe_add([])
julia> maybe_add([3, 4])
7
julia> @something(nothing, nothing, nothing)
ERROR: ArgumentError: all evaluated as `nothing`
[...]
Since @something
is often used with @?
, the form @something {ex₁; ex₂; ...; exₙ}
can also be used to avoid extra parentheses:
julia> using Maybe: @something, @?
julia> d = Dict(:a => Dict(:b => 1, :c => nothing));
julia> @something {
@? d[:A][:B];
@? d[:A][:b];
@? d[:a][:b];
@? d[:c][:d];
}
1
julia> @something(
(@? d[:A][:B]),
(@? d[:A][:b]),
(@? d[:a][:b]),
(@? d[:c][:d]),
)
1
Maybe.eltype
— FunctionMaybe.eltype(itr) -> Some(T::Type) or nothing
Return the element type of iterator if known.
Examples
julia> using Maybe
julia> Maybe.eltype(x + 0 for x in 1:3)
julia> Maybe.eltype(1:0.1:3)
Some(Float64)
Maybe.err
— FunctionMaybe.err(Err(x)) -> Some(x)
Maybe.err(Ok(_)) -> nothing
Return a Some
by re-wrapping a value inside an Err result; return nothing
on an Ok result.
See also Maybe.ok
.
Examples
julia> using Maybe, Try
julia> Maybe.err(Ok(1)) === nothing
true
julia> Maybe.err(Err(1))
Some(1)
Maybe.first
— FunctionMaybe.first(xs) -> Some(x) or nothing
Try to get the first item x
in the container xs
and return Some(x)
if exists. Return nothing
if xs
is empty.
Examples
julia> using Maybe
julia> Maybe.first([])
julia> Maybe.first([1])
Some(1)
Maybe.get
— FunctionMaybe.get(d, k) -> Some(x) or nothing
Try to get an item x
at key k
and return Some(x)
if found. Return nothing
if not found.
It is more efficient than calling haskey(dict, key)
and then dict[key]
because it does not lookup the key twice.
Examples
julia> using Maybe
julia> Maybe.get(Dict(), :a)
julia> Maybe.get(Dict(:a => 1), :a)
Some(1)
julia> Maybe.get([1], 2)
julia> Maybe.get([1], 1)
Some(1)
Maybe.getindex
— FunctionMaybge.getindex(xs, indices...) -> Some(x) or nothing
Try to get an item x
at location specified by indices
and return Some(x)
if found. Return nothing
if not found.
When xs
is an array and Maybge.getindex
is called inside @inbounds
, it always try to return Some(x)
without checking the bounds.
Examples
julia> using Maybe
julia> Maybe.getindex((11, 22, 33), 0)
julia> Maybe.getindex((11, 22, 33), 2)
Some(22)
Maybe.getproperty
— FunctionMaybe.getproperty(object, name) -> Some(property) or nothing
Return the property named name
if object
has it.
Examples
julia> using Maybe
julia> Maybe.getproperty((a = 1,), :b)
julia> Maybe.getproperty((a = 1,), :a)
Some(1)
Maybe.last
— FunctionMaybe.last(xs) -> Some(x) or nothing
Try to get the last item x
in the container xs
and return Some(x)
if exists. Return nothing
if xs
is empty.
Examples
julia> using Maybe
julia> Maybe.last([])
julia> Maybe.last([1])
Some(1)
Maybe.length
— FunctionMaybe.length(itr) -> Some(n::Integer) or nothing
Return the length of iterator if known.
Examples
julia> using Maybe
julia> Maybe.length(x for x in 1:3 if false)
julia> Maybe.length(1:3)
Some(3)
Maybe.ok
— FunctionMaybe.ok(Ok(x)) -> Some(x)
Maybe.ok(Err(_)) -> nothing
Return a Some
by re-wrapping a value inside an Ok result; return nothing
on an Err result.
See also Maybe.err
.
Examples
julia> using Maybe, Try
julia> Maybe.ok(Ok(1))
Some(1)
julia> Maybe.ok(Err(1)) === nothing
true
Maybe.Extras
Maybe.Extras
— ModuleMaybe.Extras
A namespace for extra API; this is for preserving Maybe.*
namespace for (mainly) Base
-compatible API.
Since there is no name clash with Base
API, using Maybe.Extras
imports the API defined in Maybe.Extras
.
Maybe.Extras.defaultto
— FunctionMaybe.Extras.defaultto(x)
A shorthand of ifnothing(() -> x)
.
Examples
julia> using Maybe.Extras
julia> Some(1) |> defaultto(:fallback)
1
julia> nothing |> defaultto(:fallback)
:fallback
Maybe.Extras.getnested
— FunctionMaybe.Extras.getnested(x, k₁, k₂, ..., kₙ) -> v::Union{Some{T},Nothing}
Try to get the item v = x[k₁][k₂][...][kₙ]
and return Some(v)
; return nothing
if the key does not exist.
Maybe.Extras.ifnothing
— FunctionMaybe.Extras.ifnothing(f) -> x -> ifnothing(f, x)
Maybe.Extras.ifnothing(f, nothing) -> f()
Maybe.Extras.ifnothing(f, Some(x)) -> x
See also defaultto
.
Examples
julia> using Maybe.Extras
julia> Some(1) |> ifnothing(() -> :fallback)
1
julia> nothing |> ifnothing(() -> :fallback)
:fallback
Maybe.Extras.maybe
— Functionmaybe(f) -> f′
Transform ("lift") function f(::T₁, ..., ::Tₙ) -> ::Union{Some{R}, R, Nothing}
to f′(::Union{T₁, Some{T₁}, Nothing}, ..., ::Union{Tₙ, Some{Tₙ}, Nothing}) -> ::Union{Some{R}, Nothing}
.
Examples
julia> using Maybe.Extras
julia> const ⊕ = maybe(+);
julia> 1 ⊕ nothing
julia> 1 ⊕ 2
Some(3)