I can create an anonymous function within a list comprehension in Julia. I expect that this would create a type of Vector{Function}
. Instead, the type is something like Vector{var"#2#4"}
.
For example, when involving an outer scope with an anonymous function
typeof(x->x) <: Function # true
a = 1
typeof(x-> x + a) <: Function # false
while
f(x) = x
typeof(f) <: Function # true
a = 1
g(x) = x + a
typeof(g) <: Function # true
Why is the anonymous function typed differently than the regular function when the outer scope is involved?
Now, in a list comprehension:
typeof([x->x, x->x]) <: AbstractVector{Function} # true
typeof([x->x+i for i in 1:2]) <: AbstractVector{Function} # false
typeof([x->x for i in 1:2]) <: AbstractVector{Function} # false
whether or not the index i
is involved. I initially expected true
in each case.
First note that your initial example is not correct, as you have:
julia> typeof(x->x) <: Function # true
true
julia>
julia> a = 1
1
julia> typeof(x-> x + a) <: Function
true
So both anonymous functions have a type that is a subtype of Function
.
Now as for comprehension note that this is mostly unrelated with the presence of parameter, as you have:
julia> typeof([x->x, x->x]) <: AbstractVector{Function}
true
julia> typeof([x->x]) <: AbstractVector{Function}
false
julia> typeof([x->x for i in 1:2]) <: AbstractVector{Function}
false
The reason for this behavior is when you write something like [...]
then Julia picks a narrow element type of the comprehension (if it did not try to do so you would have Any
element type - the behavior that Python have for its standard lists).
So now how to solve your issue.
To make sure that comprehension has element type of Function
you need to write:
julia> typeof(Function[x->x]) <: AbstractVector{Function}
true
julia> typeof(Function[x->x for i in 1:2]) <: AbstractVector{Function}
true
See also here and here in the manual where it explains how element type for a result of a comprehension and an array literal is picked.
If you omit the Function
prefix the element type is narrower, and in this case the proper subtyping condition would be as follows:
julia> typeof([x->x]) <: AbstractVector{<:Function}
true
julia> typeof([x->x for i in 1:2]) <: AbstractVector{<:Function}
true
(note the extra <:
).
This behavior is related to the fact that in Julia such parametric types are invariant, which is explained here in the Julia manual.