Consider the simple functions:
inner(x,a) = a*x
outer(f,x) = f(x)
If one calls outer
using a closure and global, non-constant parameter a
, we have a type-instability:
julia> a = 5; x = 2;
julia> @code_warntype outer( x -> inner(x,a), x)
Variables
#self#::Core.Compiler.Const(outer, false)
f::Core.Compiler.Const(var"#5#6"(), false)
x::Int64
Body::Any
1 ─ %1 = (f)(x)::Any
└── return %1
This is solved by declaring a
constant or wrapping the call to outer
into a function which, by itself, receives a
as a parameter, i. e. f(x,a) = outer(x->inner(x,a),x))
.
Yet, from a non-specialist point of view, these alternatives should not be necessary if the parsing of outer(x->inner(x,a),x)
translated directly to that, or to something like:
function outer2(a,x)
clos = x -> inner(a,x)
outer(clos,x)
end
That seems to be possible, since the anonymous function defined as a parameter cannot change, that is, it seems to be as constant as any other data passed to the outer
function which are constant from the point of view of the function even if they are non-constant in the global scope. The function then would specialize to the input parameters of inner
as well.
Is there a fundamental reason for that not being possible (or simple?)