-
Notifications
You must be signed in to change notification settings - Fork 30
Description
Hi!
First of all, thanks for the package, it is great.
Let me be as precise as posible. This would seem like a lot to process but it is actually quite simple to understand.
I am facing an interesting issue when defining parameters. As you may know, named tuples are nice because they are inmutable and type stable, so they can be used as a parameters container for a model (of course structs are also useful, but for this particular example I need to work with named tuples). However, if you try to do the following:
julia> using Parameters
julia> nt = (a = 1, f = t -> a + t)
(a = 1, f = var"#9#10"())
julia> nt.f(1)
ERROR: UndefVarError: a not defined
Stacktrace:
[1] (::var"#9#10")(::Int64) at .\none:1
[2] top-level scope at none:0
you get an error related to the scope of variable a.
To overcome this issue, you can use the Parameters.jl
package, specifically by means of the following macro:
julia> nt2 = @with_kw (a = 1, f = t -> a + t)
##NamedTuple_kw#511 (generic function with 2 methods)
julia> nt2()
(a = 1, f = var"#388#390"{Int64}(1))
julia> nt2().f
#388 (generic function with 1 method)
julia> nt2().f(1)
2
Also, it can handle more complex examples:
julia> nt2 = @with_kw (a = 1, f = t -> a + t, g = t -> f(t) + sin(t))
##NamedTuple_kw#255 (generic function with 2 methods)
julia> nt2().g(1.)
2.8414709848078967
This is nice. What is happening in the background is that the @with_kw macro produces a constructor function that receives named arguments so you can use them to define other parameters. You can inspect this using @macroexpand
or @expand
(from MacroTools.jl
).
Now I want to make use of these features in a more complicated example. Let's say I would like to include the numerical derivative of f in my parameters by using GSL.jl
package (I have already tested other packages but this one seems to be the fastest at the moment). The first thing I have to do, is define a gsl_function
object:
julia> using GSL
julia> const h = 9.765625e-4
0.0009765625
julia> const abserr = Cdouble[0]
const 1-element Array{Float64,1}:
0.0
julia> const result = Cdouble[0]
1-element Array{Float64,1}:
0.0
julia> nt2 = @with_kw (a = 1, f = t -> a + t, f′ = t -> deriv_central(@gsl_function(f), t, h, result, abserr))##NamedTuple_kw#262 (generic function with 2 methods)
julia> nt2()
(a = 1, f = var"#80#84"{Int64}(1), f′ = var"#81#85"())
julia> nt2().f′(0.1)
ERROR: UndefVarError: f not defined
Stacktrace:
[1] (::var"#88#89")(::Float64, ::Ptr{Nothing}) at /Users/ramirovignolo/.julia/packages/GSL/yvp3l/src/manual_wrappers.jl:45
[2] deriv_central(::gsl_function, ::Float64, ::Float64, ::Array{Float64,1}, ::Array{Float64,1}) at /Users/ramirovignolo/.julia/packages/GSL/yvp3l/src/gen/direct_wrappers/gsl_deriv_h.jl:36
[3] (::var"#81#85")(::Float64) at ./none:1
[4] top-level scope at none:1
It seems that @gsl_function
expands and uses @cfunction
(from Base). When this macro is expanded, f
is not captured. Does anyone knows how to avoid this problem at all? Thanks!!