Is there a Julia equivalent of (or well worn idiom for) Haskell’s fromMaybe
, e.g., for use with Union{T, Nothing}
?
something
seems to be it:
help?> something
search: something @something
something(x...)
Return the first value in the arguments which is not equal to nothing, if any. Otherwise throw an error. Arguments of type Some are
unwrapped.
Is it the case though that something(x, y, ...)
evaluates y
even if x
is not nothing
?
something
is a function like any other; Julia is not lazy like Haskell. Arguments are evaluated first.
(types of arguments are also not part of the type of a function)
Yeah sorry that was a dumb question. I hadn’t realized that. (But ugh!)
There’s the macro @something
for that.
Note that @something
is an AST transform (commonly known as a macro), not a function:
julia> @macroexpand @something a b
:(something(let val
#= some.jl:143 =#
if (val = a) !== nothing
val
else
if (val = b) !== nothing
val
else
nothing
end
end
end))
This works because all expressions return their last value (in this case a
, b
or nothing
as a fallback).
Is Maybe.jl
widely used? I’m new and don’t want to gum things up trying to make Julia something (see what I did there) that it isn’t. Better to deal with its idioms.
According to JuliaHub, Maybe.jl
has 0 Dependents, so I’d say no.
Usually, nothing
and missing
values are handled immediately instead of deferred to a later point in time. Maybe you can tell us more about what you want to code up and we can suggest some way of achieving it?
@something
was merged into Base. So it’s definitely idiomatic.
I can’t figure out how to invoke @something
. I’ve tried @something(...)
and Base.@something(...)
.
Just like in the @macroexpand
call I’ve used above:
julia> a = 1
1
julia> b = nothing
julia> @something a b
1
julia> @something b a
1
julia> @something b b
ERROR: ArgumentError: No value arguments present
Stacktrace:
[1] something()
@ Base ./some.jl:99
[2] something(::Nothing)
@ Base ./some.jl:100
[3] top-level scope
@ some.jl:143
Ah my bad! @something
was a very recent addition, and is not in the LTS version (or 1.6 I think).
You are right that something(...)
evaluates it’s arguments.
To emulate @something
, i.e. have fromMaybe
which isn’t eager, you can use the if...else
pattern shown above.
Yes, the @something
macro will be available from 1.7 onwards.
Use the something
function in combination with the Some
type.
Right now, just test driving the language. To actually do what I want to do it’s probably simpler (and clearer) to just do something like:
if haskey(things, n)
return things[n]
else
return a_new_thing
end
rather than
@something( get(things, n, nothing), a_new_thing )
In practice making a_new_thing
has some setup so the former makes sense anyway unless I use let
.
For reference the equivalent Haskell that inspired the question is something like
get_thing n = fromMaybe (Thing n part_1 part_2) (M.lookup n things)
where
part_1 = a_bunch_of_stuff_that_doest_fit_above
part_2 = more_stuff_that_doest_fit_above
Sounds like you want to skip the nothing
and use get!
or get
directly:
get!(f::Function, collection, key)
Return the value stored for the given key, or if no mapping for the key is present, store key => f(), and return f().
Usage:
julia> d = Dict()
Dict{Any, Any}()
julia> get!(() -> begin println("hello"); 1 end, d, "key")
hello
1
julia> get!(() -> begin println("hello"); 1 end, d, "key")
1
julia> d
Dict{Any, Any} with 1 entry:
"key" => 1
By the way, this kind of docstring can be easily accessed by using the REPL help mode, invoked by entering ?
at the REPL prompt.
That’s good, except I don’t want to store the generated one.
You can do that with get
(no exclamation mark):
julia> d = Dict()
Dict{Any, Any}()
julia> get(() -> begin println("hello"); 1 end, d, "key")
hello
1
julia> get(() -> begin println("hello"); 1 end, d, "key")
hello
1
julia> d
Dict{Any, Any}()
julia> d["key"] = 44
44
julia> get(() -> begin println("hello"); 1 end, d, "key")
44
It’s a convention (not enforced by the compiler) that functions that modify one or more of their arguments end in a !
. There’s no auto generation of such modifying functions, but most of the time when one version exists, the other does as well.