convert Julia expression to array? - julia

im getting a list that was saved as a string, and trying to parse it to use. I can use Meta.parse, to turn the string into an expression :
li = db.list
print(typeof(d[1]),d[1])
>> String
["apple", "banana", "coconut"]
parsed_li = Meta.parse(d[1])
print(typeof(parsed_li), parsed_li)
>> Expr
["apple", "banana", "coconut"]
but it doesnt seem like i can use it like a normal list ; for example, with a normal list i could access an element by its index, but i cannot access the index of the Expr object :
normal_li = ["apple", "banana", "coconut"]
print(normal_li[1])
>> apple
print(parsed_li[1])
>>
MethodError: no method matching getindex(::Expr, ::Int64)
Stacktrace:
[1] top-level scope at In[214]:8
i've been tinkering , not sure what I'm missing here!

Relying on Meta.parse() to parse your input data is both inefficient and unsafe (malicious code can be always inserted in the input data and you might be doing eval on it etc.). You rather instead use tools that are designed just for it. In your case just note that this data can be considered as a valid JSON format and can be read as follows:
julia> str = """["apple", "banana", "coconut"]"""
"[\"apple\", \"banana\", \"coconut\"]"
julia> using JSON3
julia> JSON3.read(str)
3-element JSON3.Array{String, Base.CodeUnits{UInt8, String}, Vector{UInt64}}:
"apple"
"banana"
"coconut"
julia> collect(JSON3.read(str))
3-element Vector{String}:
"apple"
"banana"
"coconut"
If you trust the input data (normally you never should) you can do it the unsafe way:
julia> eval(Meta.parse(str))
3-element Vector{String}:
"apple"
"banana"
"coconut"
If you want to extract the information without eval, it could be done using args field of the Expr object - however the way it is handled will each time strongly depend on data structure:
julia> Meta.parse(str).args
3-element Vector{Any}:
"apple"
"banana"
"coconut"

It's aways down in the docs page: evaled_li = eval(parsed_li) will be a Vector of String.

Expr is not a list-like data structure.
Quoted from the doc
Expr
A type representing compound expressions in parsed julia code (ASTs).
Each expression consists of a head Symbol identifying which kind of
expression it is (e.g. a call, for loop, conditional statement, etc.),
and subexpressions (e.g. the arguments of a call).
The subexpressions are stored in a Vector{Any} field called args.
You can still access those elements through the args field though if you want.

Related

How to correctly use jq's in() function

I'm trying to understand in() function of jq.
https://jqplay.org/s/BR1KbCjP8u
filter:
map( in(["ms", "is", "bad"]) )
input:
["apple","is","bad"]
I expected the output [false,true,true] because for each element of the input array:
"apple" is not in ["ms", "is", "bad"] so false
"is" is in ["ms", "is", "bad"] so true
"bad" is in ["ms", "is", "bad"] so true
Obviously this is wrong because I get error:
jq: error (at <stdin>:0): Cannot check whether array has a string key
exit status 5
What is wrong with this and how to correctly use the in() function when passing ["ms","is","bad"] in the filter? I want to check if each element in the input array is found in this list.
Maybe you were looking for the IN (not in) function. Also, it takes a stream of elements, not an array.
map(IN("ms", "is", "bad"))
[false,true,true]
Demo
From the manual:
in
The builtin function in returns whether or not the input key is in the given object, or the input index corresponds to an element in the given array. It is, essentially, an inversed version of has.
IN
This builtin outputs true if . appears in the given stream, otherwise it outputs false.
I was using in() incorrectly.
https://jqplay.org/s/FJcNTgplG6
filter:
map(in(["apple","is","bad"]))
input:
[3, 2, 1, 0]
output:
[
false,
true,
true,
true
]
It's testing if the indexes of the filter array are found in the input array.

How to access a Python dictionary name with string?

I have string "dict_1", and I have dictionary named dict_1.
x = "dict_1"
dict_1 = {"a": "b", "c": "d"}
So, can I access dict_1 like x['a']?
I found a Stack Overflow Question, but in this question, the OP wants to create variable with string, not access variable (dictionary) with string.
I really need some help. I'm using Python 3.8 and Windows.
Thanks!
The way I see it, you have two basic options here.
The most obvious way is to use eval to convert the value of the string x into a usable Python object - in this case the dictionary dict_1.
Note that eval executes a string as Python code. If the string is coming from an untrusted source, then this is quite dangerous to do. You should use this with caution, and apply appropriate sanitization to any inputs.
x = "dict_1"
dict_1 = {"a": "b", "c": "d"}
print(type(eval(x)))
# Prints <class 'dict'>
print(eval(x)['a'])
# Prints "b"
The other method is to make use of locals(). This returns a dictionary of variables defined in the local scope. You would index it with x, which would give you the dictionary itself as with eval.
x = "dict_1"
dict_1 = {"a": "b", "c": "d"}
print(type(locals()[x]))
# Prints <class 'dict'>
print(locals()[x]['a'])
# Prints "b"
In theory, using locals() for the job would prove to be safer since with eval, you may inadvertently execute arbitrary code.
Once again, if coming from an untrusted source, you should do some basic sanity checks, e.g. check that the variable is in scope and is a dictionary:
if x in locals() and type(locals()[x]) == dict:
print(locals()[x]['a'])
# Prints "b"

Iterate over the types in a Tuple DataType

Is there a way to iterate over the types contained in a Tuple{...} DataType? For instance, if I have the type Tuple{String, Int}, I'd like to be able to use something like values(Tuple{String, Int}) to return an iterator of String and Int, like this:
julia> collect(values(Tuple{String, Int}))
2-element Array{DataType,1}:
String
Int64
But of course that doesn't actually work:
julia> values(Tuple{String, Int})
Tuple{String,Int64}
julia> collect(values(Tuple{String, Int}))
ERROR: MethodError: no method matching length(::Type{Tuple{String,Int64}})
Closest candidates are:
length(::Core.SimpleVector) at essentials.jl:596
length(::Base.MethodList) at reflection.jl:852
length(::Core.MethodTable) at reflection.jl:938
...
Stacktrace:
[1] _similar_for(::UnitRange{Int64}, ::Type{Any}, ::Type{T} where T, ::Base.HasLength) at ./array.jl:576
[2] _collect(::UnitRange{Int64}, ::Type{T} where T, ::Base.HasEltype, ::Base.HasLength) at ./array.jl:609
[3] collect(::Type{T} where T) at ./array.jl:603
[4] top-level scope at REPL[30]:1
I would prefer a solution that does not involve digging into the internals of DataType.
A tuple type is only a DataType. Everything operating on it will have to involve DataTypes -- you're looking for a function of type DataType -> [DataType]. One possible answer is Tuple{String, Int}.parameters. At least in 1.3, Core.Compiler also contains
datatype_fieldtypes(x::DataType) = ccall(:jl_get_fieldtypes, Any, (Any,), x)
which only internal and undocumented, though. Both result in a Core.SimpleVector.
But then I remembered that tuple parts can be treated both as indices and as fields. So it turns out fieldtypes would probably be your favourite:
julia> fieldtypes(Tuple{Int, String})
(Int64, String)
The other methods, however, have the advantage that you can use them with any parametrized type. This often comes in handy in generated functions.

Purpose of "where" keyword in constructor of a parametric type

For the Julia manual parametric composite type example
struct Point{T}
x::T
y::T
end
it is possible to write an outer constructor such as
Point(x::T, y::T) where {T} = Point{T}(x, y)
Why is the where {T} part needed, i.e. why isn't
Point(x::T, y::T) = Point{T}(x, y)
possible? Julia complains that T is not defined, but could it not figure out that T is a type from the :: syntax? I am a newcomer to Julia so I might be missing something pretty basic.
T is a variable that has to be defined. If you do not define it in where Julia starts looking for it in an outer scope. Here is an example:
julia> struct Point{T}
x::T
y::T
end
julia> Point(x::T, y::T) = Point{T}(x, y)
ERROR: UndefVarError: T not defined
Stacktrace:
[1] top-level scope at REPL[2]:1
julia> T = Integer
Integer
julia> Point(x::T, y::T) = Point{T}(x, y)
Point
julia> Point(1,1)
Point{Integer}(1, 1)
Note that in this example you do not get what you expected to get, as probably you have hoped for Point{Int64}(1,1).
Now the most tricky part comes:
julia> Point(1.5,1.5)
Point{Float64}(1.5, 1.5)
What is going on you might ask. Well:
julia> methods(Point)
# 2 methods for type constructor:
[1] (::Type{Point})(x::Integer, y::Integer) in Main at REPL[4]:1
[2] (::Type{Point})(x::T, y::T) where T in Main at REPL[1]:2
The point is that The (::Type{Point})(x::T, y::T) where T already got defined by default when the struct as defined so with the second definition you have just added a new method for T = Integer.
In short - always use where to avoid getting surprising results. For example if you would write:
julia> T = String
String
julia> Point(1,1)
ERROR: MethodError: Cannot `convert` an object of type Int64 to an object of type String
you get a problem. As the signature of Point is fixed when it is defined but in the body T is taken from a global scope, and you have changed it from Integer to String, so you get an error.
Expanding on what #Oscar Smith noted the location of where is also sensitive to scope, and tells Julia on what level the "wildcard" is introduced. For example:
ulia> T1 = Vector{Vector{T} where T<:Real}
Array{Array{T,1} where T<:Real,1}
julia> T2 = Vector{Vector{T}} where T<:Real
Array{Array{T,1},1} where T<:Real
julia> isconcretetype(T1)
true
julia> isconcretetype(T2)
false
julia> T1 isa UnionAll
false
julia> T2 isa UnionAll
true
julia> x = T1()
0-element Array{Array{T,1} where T<:Real,1}
julia> push!(x, [1,2])
1-element Array{Array{T,1} where T<:Real,1}:
[1, 2]
julia> push!(x, [1.0, 2.0])
2-element Array{Array{T,1} where T<:Real,1}:
[1, 2]
[1.0, 2.0]
and you can see that T1 is a concrete type that can have an instance, and we created one calling it x. This concrete type can hold vectors whose element type is <:Real, but their element types do not have to be the same.
On the other hand T2 is a UnionAll, i.e. some of its "widlcards" are free (not known yet). However, the restriction is that in all concrete types that match T2 all vectors must have the same element type, so:
julia> Vector{Vector{Int}} <: T2
true
julia> Vector{Vector{Real}} <: T2
true
but
julia> T1 <: T2
false
In other words in T2 the wildcard must have one concrete value that can be matched by a concrete type.
I'm going to take a different tack from BogumiƂ's excellent answer (which is 100% correct, but might be missing the crux of the confusion).
There's nothing special about the name T. It's just a common convention for a short name for an arbitrary type. Kinda like how we often use the name A for matrices or i in for loops. The fact that you happened to use the same name in the struct Point{T} and in the outer constructor is irrelevant (but handy for the readers of your code). You could have just as well done:
struct Point{SpecializedType}
x::SpecializedType
y::SpecializedType
end
Point(x::Wildcard, y::Wildcard) where {Wildcard <: Any} = Point{Wildcard}(x, y)
That behaves exactly the same as what you wrote. Both of the above syntaxes (the struct and the method) introduce a new name that will behave like a "wildcard" that specializes and matches appropriately. When you don't have a where clause, you're no longer introducing a wildcard. Instead, you're just referencing types that have already been defined. For example:
Point(x::Int, y::Int) = Point{Int}(x, y)
That is, this will reference the Int that was already defined.
I suppose you could say, but if T wasn't defined, why can't Julia just figure out that it should be used as a wildcard. That may be true, but it introduces a little bit of non-locality to the syntax, where the behavior is drastically different depending upon what happens to be defined (or even exported from a used package).

Is it possible to get the return type of a Julia function in an unevaluated context?

I want to get the result type of a function call in Julia without evaluating the function, and use that type. The desired usage looks somewhat like this:
foo(x::Int32) = x
foo(x::Float32) = x
y = 0.0f0
# Assert that y has the type of result of foo(Float32)
y::#resultof foo(Float32) # This apparently does not work in Julia
While in the case above, I can simply use y::typeof(foo(1.0f0)) with evaluation of a dummy variable, in more complicated cases, initializing a dummy variable might be inconvenient and expensive. For example, I want to use the iterator type returned by function eachline(filename::AbstractString; keep::Bool=false), but using the typeof really requires opening a file successfully, which looks like an overkill.
From a C++ background, what I am asking is that is there an equivalent of std::result_of in Julia. The question is almost the same as this one but the language is Julia.
After some research I see that Julia allows for return value of different types in one function, where the type inference looks very hard. For example,
foo(x::Int64) = x == 1 ? 1 : 1.0
The return type can now be Int64 or Float64, depending on the input value. Nevertheless, in this case, I am still wondering if there are some macro tricks that can deduce that the return type is of Union{ Int64, Float64 }?
To summarize, my questions are:
Fundamentally, is it possible to get the function return type by only supplying argument types in Julia?
If 1 is not possible, for functions that have one deterministic return type (as in the 1st example), is it possible to get the return type unevaluated?
(Might be unrelated with what I want but I think it can boost my understanding) When Julia codes are compiled, are the return types of the functions known? Or is the type information only determined at run time?
1) Yes, Base.return_types(foo, (Int64,)) will return an array containing the return type you're asking for, i.e. Union{ Int64, Float64 } in this case. If you drop the second argument, a tuple specifying the input argument types, you'll get all possible infered return types.
It should be noted, however, that the compiler might at any point decide to return Any or any other correct but imprecise return type.
2) see 1) ?
3) For given input argument types, the compiler tries to infer the return type at compile-time. If multiple are possible, it will infer a Union type. If it fails completely, or there are too many different return types, it will infer Any as the return type. In the latter cases, the actual return type is only known at runtime.
Demonstration of 1):
julia> foo(x::Float32) = x
foo (generic function with 1 methods)
julia> foo(x::Int32) = x
foo (generic function with 2 methods)
julia> foo(x::Int64) = x == 1 ? 1 : 1.0
foo (generic function with 3 methods)
julia> Base.return_types(foo)
3-element Array{Any,1}:
Union{Float64, Int64}
Int32
Float32
julia> Base.return_types(foo, (Int64,))
1-element Array{Any,1}:
Union{Float64, Int64}
julia> Base.return_types(foo, (Int32,))
1-element Array{Any,1}:
Int32

Resources