How to pass a Dict to a function with Keyword arguments? - function

Let's assume I have this Dict:
d=Dict("arg1"=>10,"arg2"=>20)
and a function like this:
function foo(;arg1,arg2,arg3,arg4,arg5)
#Do something
end
How can I call the function and pass the parameters in the Dict d as parameters for the function?
I know I can do this:
foo(arg1=d["arg1"],arg2=d["arg2"])
But is there any way to automate this? I mean a way to figure out which arguments are defined in the Dict and pass it automatically to the function.

Dictionaries with Symbol keys can be directly splatted into the function call:
julia> d = Dict(:arg1 => 10, :arg2 => 12)
Dict{Symbol, Int64} with 2 entries:
:arg1 => 10
:arg2 => 12
julia> f(; arg1, arg2) = arg1 + arg2
f (generic function with 1 method)
julia> f(; d...)
22
Note the semicolon in the function call, which ensure that the elements in d are interpreted as keyword arguments instead of positional arguments which just happen to be Pairs.

Related

How to get variable names inside a function in julia

For example
function f(x)
# do something
# then I assigned the outside variable name of 'x' to y
println(y)
end
f(1)
I will get
# something and
1
then,
a = 1
f(a)
I will get
# something and
"a"
Is it possible in julia? If not, how can I get my function operation log?
The most idiomatic way would be to slightly change your interface of f and require a keyword argument:
julia> function f(;kwargs...)
for (k, v) in kwargs
println("$k = $v")
end
end
f (generic function with 1 method)
julia> f(a = 1)
a = 1
Alternatively (short of inspecting stack traces), you need something macro-based:
julia> struct Quot
expr
value
end
julia> macro quot(e)
return :($Quot($(QuoteNode(e)), $e))
end
#quot (macro with 1 method)
julia> function f2(x::Quot)
println(x)
end
f2 (generic function with 1 method)
julia> x = 2
2
julia> f2(#quot x)
Quot(:x, 2)
Depending on what you need a simples macro that dumps function calls that still get executed could be:
macro logs(expr)
#info expr
expr
end
And this can be used as:
julia> a = π/2;
julia> #logs sin(a)
[ Info: sin(a)
1.0

Declare a Julia function that returns a function with a specific signature

How can I declare a Julia function that returns a function with a specific signature. For example, say I want to return a function that takes an Int and returns an Int:
function buildfunc()::?????
mult(x::Int) = x * 2
return mult
end
What should the question marks be replaced with?
One thing needs to be made clear.
Adding a type declaration on the returned parameter is just an assertion, not part of function definition. To understand what is going on look at the lowered (this is a pre-compilation stage) code of a function:
julia> f(a::Int)::Int = 2a
f (generic function with 1 method)
julia> #code_lowered f(5)
CodeInfo(
1 ─ %1 = Main.Int
│ %2 = 2 * a
│ %3 = Base.convert(%1, %2)
│ %4 = Core.typeassert(%3, %1)
└── return %4
)
In this case since the returned type is obvious this assertion will be actually removed during the compilation process (try #code_native f(5) to see yourself).
If you want for some reason to generate functions I recommend to use the #generated macro. Be warned: meta-programming is usually an overkill for solving any Julia related problem.
#generated function f2(x)
if x <: Int
quote
2x
end
else
quote
10x
end
end
end
Now we have a function f2 where the source code of f2 is going to depend on the parameter type:
julia> f2(3)
6
julia> f2(3.)
30.0
Note that this function generation is actually happening during the compile time:
julia> #code_lowered f2(2)
CodeInfo(
# REPL[34]:1 within `f2'
┌ # REPL[34]:4 within `macro expansion'
1 ─│ %1 = 2 * x
└──│ return %1
└
)
Hope that clears things out.
You can use Function type for this purpose. From Julia documentation:
Function is the abstract type of all functions
function b(c::Int64)::Int64
return c+2;
end
function a()::Function
return b;
end
Which prints:
julia> println(a()(2));
4
Julia will throw exception for Float64 input.
julia> println(a()(2.0));
ERROR: MethodError: no method matching b(::Float64) Closest candidates are: b(::Int64)

Order of method definition gives different results

Why does the order of the method definition differ in this case? It doesn't make much sense in my opinion.
julia> f() = 1
f (generic function with 1 method)
julia> f(;arg) = 1
f (generic function with 1 method)
julia> f()
ERROR: UndefKeywordError: keyword argument arg not assigned
Stacktrace:
[1] f() at ./REPL[2]:1
[2] top-level scope at REPL[3]:1
julia> f() = 1
f (generic function with 1 method)
julia> f()
1
julia> f(arg=1)
1
The order of method definition gives different result because of how function
with keyword arguments fits into the mechanics of method dispatch in Julia 1.x.
As pointed in the comments above, the short answer is: because the second definition completely overwrites the other.
But I think this is not completely exact, lets see.
Case 1: with the order:
julia> f() = 2
f (generic function with 1 method)
julia> f(;arg) = 1
f (generic function with 1 method)
julia> f()
ERROR: UndefKeywordError: keyword argument arg not assigned
The user defined function f() is overridden.
Case 2: reversing the order both methods are visible:
julia> f(;arg) = 1
f (generic function with 1 method)
julia> f() = 2
f (generic function with 1 method)
julia> f()
2
julia> f(arg=3)
1
When f(;arg) is lowered the compiler produces the method f(), without keyword arguments,
to handle the case where no keyword arguments are passed.
This produce two different outcomes:
Case 1: the produced method f() overrides the user defined f().
Case 2: the user defined f() overrides the produced method f() but f(;args) remains visible.
Note that from both cases it seems that as final result
we get a function f with 1 method, but indeed in the second case we have effectively 2 functions with 1 method each,
one that manage the user defined f() and one that manages the keyword arguments version f(;arg).
The full details of how keyword arguments method definition is lowered is detailed
in the docs

Constructor of derived types

I am trying to write a constructor for a derived type of an abstract one to solve this other question, but it seems that it's not working, or better, it isn't called at all.
The aim is to have a runtime polymorphism setting the correct number of legs of an animal.
These are the two modules:
animal
module animal_module
implicit none
type, abstract :: animal
private
integer, public :: nlegs = -1
contains
procedure :: legs
end type animal
contains
function legs(this) result(n)
class(animal), intent(in) :: this
integer :: n
n = this%nlegs
end function legs
cat
module cat_module
use animal_module, only : animal
implicit none
type, extends(animal) :: cat
private
contains
procedure :: setlegs => setlegs
end type cat
interface cat
module procedure init_cat
end interface cat
contains
type(cat) function init_cat(this)
class(cat), intent(inout) :: this
print *, "Cat!"
this%nlegs = -4
end function init_cat
main program
program oo
use animal_module
use cat_module
implicit none
type(cat) :: c
type(bee) :: b
character(len = 3) :: what = "cat"
class(animal), allocatable :: q
select case(what)
case("cat")
print *, "you will see a cat"
allocate(cat :: q)
q = cat() ! <----- this line does not change anything
case default
print *, "ohnoes, nothing is prepared!"
stop 1
end select
print *, "this animal has ", q%legs(), " legs."
print *, "cat animal has ", c%legs(), " legs."
end program
The constructor isn't called at all, and the number of legs still remains to -1.
The available non-default constructor for the cat type is given by the module procedure init_cat. This function you have defined like
type(cat) function init_cat(this)
class(cat), intent(inout) :: this
end function init_cat
It is a function with one argument, of class(cat). In your later reference
q = cat()
There is no specific function under the generic cat which matches that reference: the function init_cat does not accept a no-argument reference. The default structure constructor is instead used.
You must reference the generic cat in a way matching your init_cat interface to have that specific function called.
You want to change your init_cat function to look like
type(cat) function init_cat()
! print*, "Making a cat"
init_cat%nlegs = -4
end function init_cat
Then you can reference q=cat() as desired.
Note that in the original, you are attempting to "construct" a cat instance, but you aren't returning this constructed entity as the function result. Instead, you are modifying an argument (already constructed). Structure constructors are intended to be used returning such useful things.
Note also that you don't need to
allocate (cat :: q)
q = cat()
The intrinsic assignment to q already handles q's allocation.
FWIW, here is some sample code comparing three approaches (method = 1: sourced allocation, 2: polymorphic assignment, 3: mixed approach).
module animal_module
implicit none
type, abstract :: animal_t
integer :: nlegs = -1
contains
procedure :: legs !! defines a binding to some procedure
endtype
contains
function legs(this) result(n)
class(animal_t), intent(in) :: this
!! The passed variable needs to be declared as "class"
!! to use this routine as a type-bound procedure (TBP).
integer :: n
n = this % nlegs
end
end
module cat_module
use animal_module, only : animal_t
implicit none
type, extends(animal_t) :: cat_t
endtype
interface cat_t !! overloads the definition of cat_t() (as a procedure)
module procedure make_cat
end interface
contains
function make_cat() result( ret ) !! a usual function
type(cat_t) :: ret !<-- returns a concrete-type object
ret % nlegs = -4
end
end
program main
use cat_module, only: cat_t, animal_t
implicit none
integer :: method
type(cat_t) :: c
class(animal_t), allocatable :: q
print *, "How to create a cat? [method = 1,2,3]"
read *, method
select case ( method )
case ( 1 )
print *, "1: sourced allocation"
allocate( q, source = cat_t() )
!! An object created by a function "cat_t()" is used to
!! allocate "q" with the type and value taken from source=.
!! (Empirically most stable for different compilers/versions.)
case ( 2 )
print *, "2: polymorphic assignment"
q = cat_t()
!! Similar to sourced allocation. "q" is automatically allocated.
!! (Note: Old compilers may have bugs, so tests are recommended...)
case ( 3 )
print *, "3: mixed approach"
allocate( cat_t :: q )
q = cat_t()
!! First allocate "q" with a concrete type "cat_t"
!! and then assign a value obtained from cat_t().
case default ; stop "unknown method"
endselect
c = cat_t()
!! "c" is just a concrete-type variable (not "allocatable")
!! and assigned with a value obtained from cat_t().
print *, "c % legs() = ", c % legs()
print *, "q % legs() = ", q % legs()
end
--------------------------------------------------
Test
$ gfortran test.f90 # using version 8 or 9
$ echo 1 | ./a.out
How to create a cat? [method = 1,2,3]
1: sourced allocation
c % legs() = -4
q % legs() = -4
$ echo 2 | ./a.out
How to create a cat? [method = 1,2,3]
2: polymorphic assignment
c % legs() = -4
q % legs() = -4
$ echo 3 | ./a.out
How to create a cat? [method = 1,2,3]
3: mixed approach
c % legs() = -4
q % legs() = -4
--------------------------------------------------
Side notes
* It is also OK to directly use make_cat() to generate a value of cat_t:
e.g., allocate( q, source = make_cat() ) or q = make_cat().
In this case, we do not need to overload cat_t() via interface.
* Another approach is to write an "initializer" as a type-bound procedure,
and call it explicitly as q % init() (after allocating it via
allocate( cat_t :: q )). If the type contains pointer components,
this approach may be more straightforward by avoiding copy of
components (which can be problematic for pointer components).

Fortran error in passing function

I am trying writing a simple Fortran code that calculates h = g(f(x)). The x is a vector of length=2.
module m1
implicit none
contains
function f(x)
implicit none
real::f(2),x(2)
f(1)=x(1)-x(2)
f(2)=exp(x(1))-x(2)**2
end function f
function g(ff)
implicit none
real::g(2),x1(2),ffreslt(2)
interface
function ff(x)
implicit none
real::x(2),ff(2)
end function ff
end interface
ffreslt=ff(x1)
g(1)=1-ffreslt(1)
g(2)=2*ffreslt(1)**2-3*ffreslt(2)+4.2
end function g
end module m1
program hgf
use m1
implicit none
real::x1(2),h(2)
x1 = (/0.55,2.47/)
h = g(f(x1))
write(*,*) h
end program hgf
But, I am getting this error message:
h = g(f(x1))
1
Error: Actual parameter 'ff' at <1> is not a PROCEDURE
Am I missing something? Thanks.
in the call to g() you are not passing the function f() but rather the result of calling the function f() with the value of x1.
Check this Notes on converting from F77 to F90 and look at page 24, Section 3.2.7.
Also check this question on procedures as arguments.