Add and call Function to and from Dict in Julia - julia

assume I have a Dict
acts = Dict{String, Function}()
and I have a function foo()
function foo(arg1, arg2)
#info arg1
#info arg2
end
First, How can I store "bar" => foo() in acts Dict?
Second, How can I call bar from acts and run it?

Should be straightforward:
julia> acts = Dict{String, Function}()
Dict{String,Function} with 0 entries
julia> function foo(arg1, arg2)
#info arg1
#info arg2
end
foo (generic function with 1 method)
# add function foo to dict acts with key "bar"
julia> acts["bar"] = foo
foo (generic function with 1 method)
# check that it's there
julia> acts
Dict{String,Function} with 1 entry:
"bar" => foo
# call the foo function from the dict by using its key
julia> acts["bar"]("hi", 2)
[ Info: hi
[ Info: 2

Related

Filtering a dictionary in julia

I want to filter a dictionary using filter() function but I am having trouble with it. What I wish to accomplish is, to return the key for some condition of the value. However I am getting a method error
using Agents: AbstractAgent
# Define types
mutable struct Casualty <: AbstractAgent
id::Int
ts::Int
rescued::Bool
function Casualty(id,ts; rescued = false)
new(id,ts,rescued)
end
end
mutable struct Rescuer <: AbstractAgent
id::Int
actions::Int
dist::Float64
function Rescuer(id; action = rand(1:3) , dist = rand(1)[1])
new(id,action,dist)
end
end
cas1 = Casualty(1,2)
cas2 = Casualty(2,3)
resc1 = Rescuer(3)
agents = Dict(1=> cas1, 2 => cas2, 3 => resc1)
Now to filter
filter((k,v) -> v isa Casualty, agents)
# ERROR: MethodError: no method matching (::var"#22#23")(::Pair{Int64, AbstractAgent})
# what I truly wish to achieve is return the key for some condition of the value
filter((k,v) -> k ? v isa Casualty : "pass", agents)
# ofcourse I am not sure how to "pass" using this format
Any idea how I can achieve this. Thanks
For dictionaries filter gets a key-value pair, so do either (destructuring Pair):
julia> dict = Dict(1=>"a", 2=>"b", 3=>"c")
Dict{Int64, String} with 3 entries:
2 => "b"
3 => "c"
1 => "a"
julia> filter(((k,v),) -> k == 1 || v == "c", dict)
Dict{Int64, String} with 2 entries:
3 => "c"
1 => "a"
or for example (getting Pair as a whole):
julia> filter(p -> first(p) == 1 || last(p) == "c", dict)
Dict{Int64, String} with 2 entries:
3 => "c"
1 => "a"
julia> filter(p -> p[1] == 1 || p[2] == "c", dict)
Dict{Int64, String} with 2 entries:
3 => "c"
1 => "a"
EDIT
Explanation why additional parentheses are needed:
julia> f = (x, y) -> (x, y)
#1 (generic function with 1 method)
julia> g = ((x, y),) -> (x, y)
#3 (generic function with 1 method)
julia> methods(f)
# 1 method for anonymous function "#1":
[1] (::var"#1#2")(x, y) in Main at REPL[1]:1
julia> methods(g)
# 1 method for anonymous function "#3":
[1] (::var"#3#4")(::Any) in Main at REPL[2]:1
julia> f(1, 2)
(1, 2)
julia> f((1, 2))
ERROR: MethodError: no method matching (::var"#1#2")(::Tuple{Int64, Int64})
Closest candidates are:
(::var"#1#2")(::Any, ::Any) at REPL[1]:1
julia> g(1, 2)
ERROR: MethodError: no method matching (::var"#3#4")(::Int64, ::Int64)
Closest candidates are:
(::var"#3#4")(::Any) at REPL[2]:1
julia> g((1, 2))
(1, 2)
As you can see f takes 2 positional argument, while g takes one positional argument that gets destructured (i.e. the assumption is that argument passed to g is iterable and has at least 2 elements).
See also https://docs.julialang.org/en/v1/manual/functions/#Argument-destructuring.
Now comes the tricky part:
julia> h1((x, y)) = (x, y)
h1 (generic function with 1 method)
julia> methods(h1)
# 1 method for generic function "h1":
[1] h1(::Any) in Main at REPL[1]:1
julia> h2 = ((x, y)) -> (x, y)
#1 (generic function with 1 method)
julia> methods(h2)
# 1 method for anonymous function "#1":
[1] (::var"#1#2")(x, y) in Main at REPL[3]:1
In this example h1 is a named function. In this case it is enough to just wrap arguments in extra parentheses to get destructuring behavior. For anonymous functions, because of how Julia parser works an extra , is needed - if you omit it the extra parentheses are ignored.
Now let us check filter docstring:
filter(f, d::AbstractDict)
Return a copy of d, removing elements for which f is false.
The function f is passed key=>value pairs.
As you can see from this docstring f is passed a single argument that is Pair. That is why you need to use either destructuring or define a single argument function and extract its elements inside the function.
The right syntax is:
filter(((k,v),) -> v isa Casualty, agents)
which prints
julia> filter(((k,v),) -> v isa Casualty, agents)
Dict{Int64, AbstractAgent} with 2 entries:
2 => Casualty(2, 3, false)
1 => Casualty(1, 2, false)
About the problem of only getting involved keys... I have no idea beside:
julia> filter(((k,v),) -> v isa Casualty, agents) |> keys
which prints
julia> filter(((k,v),) -> v isa Casualty, agents) |> keys
KeySet for a Dict{Int64, AbstractAgent} with 2 entries. Keys:
2
1

Break Function without return

I have a function
function foo(a)
if a > 5
a = 5
end
some_more_code
end
If the if-statement is true I would like to end the function but I don't want to return anything - to change the value of a is all I need.
How do I do that?
You can write (note that I have also changed the syntax of function definition to make it more standard for Julia style):
function foo(a)
if a > 5
a = 5
return
end
# some_more_code
end
Just use the return keyword without any expression following it. To be precise in such cases Julia returns nothing value of type Nothing from a function (which is not printed in REPL and serves to signal that you did not want to return anything from a function).
Note though that the value of a will be only changed locally (within the scope of the function), so that outside of the function it will be unchanged:
julia> function foo(a)
if a > 5
a = 5
return
end
# some_more_code
end
foo (generic function with 1 method)
julia> x = 10
julia> foo(x)
julia> x
10
In order to make the change visible outside of the function you have to make a to be some kind of container. A typical container for such cases is Ref:
julia> function foo2(a)
if a[] > 5
a[] = 5
return
end
# some_more_code
end
foo2 (generic function with 1 method)
julia> x = Ref(10)
Base.RefValue{Int64}(10)
julia> foo2(x)
julia> x[]
5

How to pass a function typesafe in julia

Let's say, I want to pass a function to another function:
function foo()
return 0;
end
function bar(func)
return func();
end
print(bar(foo));
But you can make functions typesafe:
function func(t::Int)
print(t);
end
func(0); #produces no error
func("Hello world"); #produces an error
I didn't found out, how I combine both, that means, how can I explicitly define a parameter of bar, like func, to be a function, possibly with certain input / output argument types.
Thanks in advance for any help.
If I understand you correctly you want to make sure the passed function returns a specific type? The simplest thing is to just typeassert the return value at runtime:
julia> function f(func)
val = func()::Int # Error if the return value is not of type Int
return val
end
f (generic function with 1 method)
julia> f(() -> 1)
1
julia> f(() -> 1.0)
ERROR: TypeError: in typeassert, expected Int64, got Float64
Stacktrace:
[1] f(::var"#7#8") at ./REPL[5]:2
[2] top-level scope at REPL[8]:1
Alternatively you can use the FunctionWrappers.jl package (which will convert to the specified return type, or error if the conversion is not possible):
julia> using FunctionWrappers: FunctionWrapper
julia> function f(func::FunctionWrapper{Int,<:Tuple})
val = func()
return val
end;
julia> function f(func)
fw = FunctionWrapper{Int,Tuple{}}(func)
return f(fw)
end;
julia> f(() -> 1)
1
julia> f(() -> 1.0) # Can convert to Int
1
julia> f(() -> 1.2) # Can not convert to Int
ERROR: InexactError: Int64(1.2)
A function is of type Function. You can easily check this:
julia> foo() = 1;
julia> T = typeof(foo)
typeof(foo)
julia> supertype(T)
Function
julia> foo isa Function
true
This will not necessarily cover all callable types, as you can make any type callable:
julia> struct Callable end
julia> (::Callable)(x::Number) = x + one(x)
julia> callable = Callable()
Callable()
julia> callable(5)
6
julia> callable isa Function
false

Invoking parent functors in Julia

Since version 1.3 Julia allows functor dispatch on abstract types. Therefore, I was wondering whether it is possible to explicitly invoke the parent functor from a child object.
E.g. in the example below, is there any way to call (x::Foo)() through the bar::Bar object?
abstract type Foo end
(x::Foo)() = "Invoked Foo functor."
struct Bar <: Foo end
(x::Bar)() = "Invoked Bar functor."
bar = Bar()
#info "Calling bar functor directly."
bar() |> println
#info "Invoking parent functor."
# ??? - how to invoke parent functor (x::Foo)() (e.g. desired output "Invoked Foo functor")
invoke(bar,Tuple{Bar}, bar) |> println
what about using a default struct?
abstract type Foo end
(x::Foo)() = "Invoked Foo functor."
struct Bar <: Foo end
(x::Bar)() = "Invoked Bar functor."
struct DefaultFoo <: Foo end
#here we dont define an specialized method, DefaultFoo calls Foo
#an interface to define default methods:
default(x::Type{Foo}) = DefaultFoo
function parent(x::T) where {T}
y = default(supertype(T))
return y()
end
finally, you can do this to call the default function:
bar = Bar()
foo = parent(bar)
foo()
this requires a definition of a defaultFoo type and a default(x::Type{T}) for each supertype . you can automate this with the following macro:
macro create_default_functor(type)
a = gensym(type)
esc(quote
struct $a <: $type end
default(x::Type{$type}) = $a
end)
end
using the macro, and your code:
abstract type Foo end
(x::Foo)() = "Invoked Foo functor."
#create_default_functor Foo
struct Bar <: Foo end
(x::Bar)() = "Invoked Bar functor."
function parent(x::T) where {T}
y = default(supertype(T))
return y()
end
#calling bar
bar = Bar()
bar()
#calling foo
foo = parent(bar)
foo()
I don't have the macro knowledge right now to call the macro directly on the abstract type definition, but is a start.
The thing about abstract functors is that is a very new feature (1.3 is not out yet) and maybe this can be added on future versions of julia (something like call_parent(Foo,args...), ) if you add a PR suggesting the feature.

Julia-Lang Metaprogramming: turn expression into function with expression-dependent arguments

Given a dictionary of values,
values = {:A => 3, :B => 1}
turn an (arbitrary) expression like
expr = :(2*A)
into a function foo(values) that evaluates the expression, so in this case foo(values) = 6. The resulting function will be called millions of times, so speed is an important consideration. I am happy to adopt a slightly different approach if necessary, as long as it can be automatised.
Things I tried:
The conversion using convert(Function, expr), as suggested here. Fails for me (Julia 0.3.8-pre):
convert has no method matching convert(::Type{Function}, ::Expr)
Using #eval one can do
#eval foo(A) = $(expr)
and then call foo(values[:A]), but that would require knowing that expr depends on A (and only on A).
I wrote a function find_vars(exp) to return the symbols in expr (in this case [:A]), but couldn't find how to use them in the #eval approach.
Base.Cartesian has an unexported function lreplace which may be what you're after. Then you can do something like:
julia> values = Dict(:A=>3, :B=>1)
Dict{Symbol,Int64} with 2 entries:
:B => 1
:A => 3
julia> import Base.Cartesian.lreplace
julia> expr = :(2*A)
:(2A)
julia> function lreplace_all(expr, d)
for (k, v) in d
expr = lreplace(expr, k, v)
end
expr
end
lreplace_all (generic function with 1 method)
julia> lreplace_all(expr, values)
:(2 * 3)
julia> #eval foo(A) = $(lreplace_all(:(2A), values))
foo (generic function with 1 method)
julia> foo(1)
6
Although, since A is defined by the values dict, it makes more sense to define foo as a zero-argument function (unless I've missed something).
EDIT:
After rereading your question it seems like you want to pass in the actual dictionary to the function rather than have the values available at compile time as I've done above. In that case, we have get a little creative:
First we need an lreplace like function that will work with expressions which is easy enough
julia> dictreplace!(ex, s, v) = ex
dictreplace! (generic function with 1 method)
julia> dictreplace!(ex::Symbol, s, v) = s == ex ? v : ex
dictreplace! (generic function with 2 methods)
julia> function dictreplace!(ex::Expr, s, v)
for i=1:length(ex.args)
ex.args[i] = dictreplace!(ex.args[i], s, v)
end
ex
end
dictreplace! (generic function with 3 methods)
julia> dictreplace(ex, s, v) = dictreplace!(copy(ex), s, v)
dictreplace (generic function with 1 method)
Now we want to replace every occurence of a symbol in our dict keys with a dictionary lookup
julia> function dictreplace_all(expr, kys, dsym)
for k in kys
expr = dictreplace(expr, k, :($(dsym)[$(QuoteNode(k))]))
end
expr
end
dictreplace_all (generic function with 1 method)
julia> dictreplace_all(:(2A), keys(values), :d)
:(2 * d[:A])
julia> #eval foo(args) = $(dictreplace_all(:(2A), keys(values), :args))
foo (generic function with 1 method)
julia> values[:A] = -99
-99
julia> foo(values)
-198
Thanks to the solution by #ptb and another metaprogramming question I found a simpler yet slower solution:
function foo(values, expr)
expr = quote
A = values[:A]
B = values[:B]
return $(expr)
end
eval(expr)
end
Reading in the values from the dictionary can also be done programmatically by replacing the inner evaluation by
$([:($k = $v) for (k, v) in values]...)
return $(expr)

Resources