For example in the code below, x is defining the domain, but why is there the double dot between 0 and 4pi?
using ApproxFun
x=Fun(identity,0..4π)
.. is an operator (like e.g. +) but it does not have a default definition. You can define it to to whatever you want:
julia> ..(a, b) = println(a, ", ", b)
.. (generic function with 1 method)
julia> "hello" .. "world"
hello, world
The Julia package IntervalArithmetic uses it to construct an interval, e.g.
julia> using IntervalArithmetic
julia> 4..5
[4, 5]
julia> typeof(4..5)
Interval{Float64}
and I suspect this is what it is used for in your code example.
.. is not part of Julia, rather part of the packages used by ApproxFun.
It is used to represent intervals, see the code below
julia> u = 1..3
1..3
julia> dump(u)
Interval{:closed,:closed,Int64}
left: Int64 1
right: Int64 3
So this is just a convenience constructor for the Interval object, see:
julia> 1..3 === Interval{:closed,:closed,Int64}(1,3)
true
Related
I use lots of Int32s in my code because I have some large arrays of those. But for some x::Int32 we have typeof(x+1) == Int64 since numeric literals are Int64 by default (I have to use 64bit Julia to handle my arrays). The problem is, if I have some function f(x::Int32) then f(x+1) will method error. I don't want to implement a f(x::Int64) = f(convert(Int32, x)) for almost every function and want to use concrete types for type stability. Currently, I simply have expressions like x + Int32(1) all over my code which looks really cluttered. For other types we have shorthands, i.e., 1.f0 gives me a Float32 and big"1" a BigInt. Is there something similar for Int32?
Since you explicitly mention the big_str macro (big"") you can easily define a similar macro for Int32 (the same way the uint128_str and int128_str is defined):
macro i32_str(s)
parse(Int32, s)
end
julia> typeof(i32"1")
Int32
this might still clutter your code too much so alternatively you could exploit that a number followed by a name is multiplication:
struct i32 end
(*)(n, ::Type{i32}) = Int32(n)
julia> typeof(1i32)
Int32
You can make a macro to replace every literal integer with an Int32, a bit like what ChangePrecision.jl does for floats. A very quick first attempt is:
julia> macro literal32(ex)
esc(literal32(ex))
end;
julia> literal32(ex::Expr) = Expr(ex.head, literal32.(ex.args)...);
julia> literal32(i::Int) = Int32(i);
julia> literal32(z) = z; # ignore Symbol, literal floats, etc.
julia> #literal32 [1,2] .+ 3
2-element Vector{Int32}:
4
5
julia> #literal32 function fun(x::AbstractVector)
x[1] + 2 # both 1 and 2 are changed
end
fun (generic function with 1 method)
julia> fun(Int32[3,4]) |> typeof
Int32
One place this may have unexpected consequences is literal type parameters:
julia> #literal32([1,2,3]) isa Array{Int32,1}
true
julia> #literal32 [1,2,3] isa Array{Int32,1}
false
Another is that x^2 will not use Base.literal_pow, e.g. #literal32 Meta.#lower pi^2.
What if you say:
# Or, a::Int32 = 1
julia> a = Int32(1)
1
julia> b::Int32 = a+2
3
julia> typeof(b)
Int32
julia> f(b)
...
I am creating a non-standard string literal with a macro with something like that:
macro R13_str(p)
rotate(13, p)
end
and it works. I can call it as:
R13"abc"
But I would like to declare the macro to work with any integer, like:
R1"abc"
or
R244"abc"
Let's say the function rotate() is:
function rotate(shift_amount::Int64, s::String)
# Ensure the shift is no bigger than the string
shift = shift_amount ≤ length(s) ? shift_amount : shift_amount % length(s)
# Circular shift
return s[end-shift+1:end] * s[1:end-shift]
end
How can I do that? I have checked all the docs, but it's not clear to me.
Can't see how to achieve exactly what is required. But the following might be good enough:
julia> macro R_str(p,flag)
rotate(flag, p)
end
#R_str (macro with 1 method)
julia> R"hello"3
"llohe"
julia> R"abc"1
"cab"
julia> R"abc"244
"cab"
See https://docs.julialang.org/en/v1/manual/metaprogramming/#meta-non-standard-string-literals
Trying to conform to OP call format:
julia> macro rework(expr)
if expr.head != :macrocall return expr ; end
r = String(expr.args[1])
rr = parse(Int, r[3:findfirst('_',r)-1])
:(rotate($rr, $(expr.args[3])))
end
#rework (macro with 1 method)
julia> #rework R13"hello"
"llohe"
This macro could help to read the prepared test cases??
I have found a solution:
for n in 0:244
#eval macro $(Symbol(:R, n, :_str))(s)
rotate($n, s)
end
end
While I believe that using flags is the better approach, with this for loop I can generate all the macros that I need.
Julia> R1"abc"
Julia> R24"acb"
Julia> R56"abc"
simply work.
I'm trying to build a function that will output an expression to be assigned to a new in-memory function. I might be misinterpreting the capability of metaprogramming but, I'm trying to build a function that generates a math series and assigns it to a function such as:
main.jl
function series(iter)
S = ""
for i in 1:iter
a = "x^$i + "
S = S*a
end
return chop(S, tail=3)
end
So, this will build the pattern and I'm temporarily working with it in the repl:
julia> a = Meta.parse(series(4))
:(x ^ 1 + x ^ 2 + x ^ 3 + x ^ 4)
julia> f =eval(Meta.parse(series(4)))
120
julia> f(x) =eval(Meta.parse(series(4)))
ERROR: cannot define function f; it already has a value
Obviously eval isn't what I'm looking for in this case but, is there another function I can use? Or, is this just not a viable way to accomplish the task in Julia?
The actual error you get has to do nothing with metaprogramming, but with the fact that you are reassigning f, which was assigned a value before:
julia> f = 10
10
julia> f(x) = x + 1
ERROR: cannot define function f; it already has a value
Stacktrace:
[1] top-level scope at none:0
[2] top-level scope at REPL[2]:1
It just doesn't like that. Call either of those variables differently.
Now to the conceptual problem. First, what you do here is not "proper" metaprogramming in Julia: why deal with strings and parsing at all? You can work directly on expressions:
julia> function series(N)
S = Expr(:call, :+)
for i in 1:N
push!(S.args, :(x ^ $i))
end
return S
end
series (generic function with 1 method)
julia> series(3)
:(x ^ 1 + x ^ 2 + x ^ 3)
This makes use of the fact that + belongs to the class of expressions that are automatically collected in repeated applications.
Second, you don't call eval at the appropriate place. I assume you meant to say "give me the function of x, with the body being what series(4) returns". Now, while the following works:
julia> f3(x) = eval(series(4))
f3 (generic function with 1 method)
julia> f3(2)
30
it is not ideal, as you newly compile the body every time the function is called. If you do something like that, it is preferred to expand the code once into the body at function definition:
julia> #eval f2(x) = $(series(4))
f2 (generic function with 1 method)
julia> f2(2)
30
You just need to be careful with hygiene here. All depends on the fact that you know that the generated body is formulated in terms of x, and the function argument matches that. In my opinion, the most Julian way of implementing your idea is through a macro:
julia> macro series(N::Int, x)
S = Expr(:call, :+)
for i in 1:N
push!(S.args, :($x ^ $i))
end
return S
end
#series (macro with 1 method)
julia> #macroexpand #series(4, 2)
:(2 ^ 1 + 2 ^ 2 + 2 ^ 3 + 2 ^ 4)
julia> #series(4, 2)
30
No free variables remaining in the output.
Finally, as has been noted in the comments, there's a function (and corresponding macro) evalpoly in Base which generalizes your use case. Note that this function does not use code generation -- it uses a well-designed generated function, which in combination with the optimizations results in code that is usually equal to the macro-generated code.
Another elegant option would be to use the multiple-dispatch mechanism of Julia and dispatch the generated code on type rather than value.
#generated function series2(p::Val{N}, x) where N
S = Expr(:call, :+)
for i in 1:N
push!(S.args, :(x ^ $i))
end
return S
end
Usage
julia> series2(Val(20), 150.5)
3.5778761722367333e43
julia> series2(Val{20}(), 150.5)
3.5778761722367333e43
This task can be accomplished with comprehensions. I need to RTFM...
https://docs.julialang.org/en/v1/manual/arrays/#Generator-Expressions
While experimenting with Julia 1.0, I've noticed that I can do something like this:
x\y = 1
The REPL then shows:
\ (generic function with 1 method)
which means its a valid assignment (the interpreter doesn't complain). However, x, y, and x\y all remain undefined.
What is the meaning of such expression?
It is a new function definition that (kind of) shadows the left division operator \ in Base, since the left division operator is already defined for some types in Julia. The new function definition is \(x,y) = 1 (the names of function parameters do not matter) which works for all types of variables. This will prevent julia from loading Base.\ due to name conflict. No matter what the input is your new \ will return the same value.
julia> x\y = 5
julia> a = 3; b = 4;
julia> a\b
5
julia> c = "Lorem ipsum"; d = "dolor";
julia> c\d
5
If you have already used the \ that is defined in Base, your redefinition will throw an error saying that extending Base.\ requires an explicit import with import Base.\. The behavior of defining \ after import Base.\ however will be different. It will extend the operator Base.\.
julia> 1\[1,3]
2-element Array{Float64,1}:
1.0
3.0
julia> import Base.\
julia> x\y=3
\ (generic function with 152 methods)
julia> 1\[1,3]
2-element Array{Int64,1}:
3
3
I have a function, f. I want to add a method that takes any container of Strings. For example, I want to write a method that generates the following when needed:
f(xs::Array{String, 1}) = ...
f(xs::DataArray{String, 1}) = ...
f(xs::ITERABLE{String}) = ...
Is this possible to do in Julia's type system? Right now, I'm using a macro to write a specialized method when I need it.
#make_f(Array{String, 1})
#make_f(DataArray{String, 1})
This keeps things DRY, but it feels...wrong.
Can't you just use duck typing? I.e., just assume that you're feeding the function an object of the right type and throw an error if at some point e.g. you don't have a string in your iterable.
This should improve once you can really talk about iterables using traits; currently there is no iterable type. Scott's answer, for example, will not work with a tuple of strings, even though that is iterable.
E.g.
julia> f(x) = string(x...) # just concatenate the strings
f (generic function with 1 method)
julia> f(("a", "á"))
"aá"
julia> f(["a", "á"])
"aá"
julia> f(["a" "b"; "c" "d"]) # a matrix of strings!
"acbd"
At least in Julia 0.4, the following should work:
julia> abstract Iterable{T} <: AbstractVector{T}
julia> f{T<:Union{Vector{String},Iterable{String}}}(xs::T) = 1
f (generic function with 1 method)
julia> x = String["a", "é"]
2-element Array{AbstractString,1}:
"a"
"é"
julia> f(x)
1