I'm getting started with the Julia programming language and I'm not really understanding the "end" syntax.
function foo(s, d, m)
res = 0
for i in range(0,length(s)-m)
tmp = 0
for j in range(0,m)
tmp += s[i+m]
end
if tmp == d
res++
end
end
return res
end
Running this code I get
LoadError: syntax: unexpected "end"
in expression starting at untitled-eae5b84e07787c95497e056f34423071:10
How should I fix my function?
Julia does not increment with res++. Instead, write
res += 1
Related
I went to this error by chance which I fixed with some diverted way, but still I was curious how it is solved for Julia.
Suppose the MWE:
julia> a = 1 ; b = 5 ; some_logical_value = true
julia> #assert a > 0 ? b in 1:10 : some_logical_value
ERROR: syntax: space required before colon in "?" expression
Stacktrace:
[1] top-level scope at none:1
Which yields an error as, not surprisingly : from ternary operator and : from 1:10 is misleading for Julia. How should we do so?
You just need to add parentheses enclosing the range expression, so either of
#assert a > 0 ? b in (1:10) : some_logical_value
or
#assert a > 0 ? (b in 1:10) : some_logical_value
should work.
I have a function within which I would like to evaluate a list of expressions using interpolated literals passed as arguments to the function and assign the result to a new array. Previously I've been able to do this fairly simply:
array_of_expr = Any[:(A * 5), :(B * 6 * T)]
arglist = [:A; :B; :T]
test_input = [1e5, 1e1, 100]
#eval begin
function interpolate_all($(arglist...))
result_array = $(Expr(:vcat, array_of_expr...))
end
end
interpolate_all(test_input...)
which returns the expected result:
2-element Array{Float64,1}:
500000.0
6000.0
(I know the code seems needlessly complicated with the #eval--it's because in the full version of the code, arglist is ~500 items long. This has been causing some compiler errors in the full version of the code, so my attempts here to loop over array_of_expr are part of my testing to find out the exact error, and also help me better understand metaprogramming/variable scope while I'm at it.)
I can index array_of_expr and evaluate an individual elements manually in this MWE:
#eval begin
function interpolate_one($(arglist...))
result_array = similar(array_of_expr)
println("evaluating $(array_of_expr[2])")
result_array = $(array_of_expr[2])
println(result_array)
end
end
interpolate_one(test_input...)
which returns:
evaluating B * 6 * T
6000.0
Which is the expected behavior. But if I try to loop over array_of_expr, I encounter various errors. The following ignores the iterator i and just prints the symbolic expression:
#eval begin
function interpolate_1by1($(arglist...))
result_array = similar(array_of_expr)
# this doesn't work, it just gives the symbolic expression, basically ignoring the $:
for i in range(1, length=length(array_of_expr))
result_array[i] = ($array_of_expr[i])
end
println(result_array)
end
end
interpolate_1by1(test_input...)
The following reports that i is not defined, which I understand is because expressions are evaluated in the global scope, not local:
#eval begin
function interpolate_1by1($(arglist...))
result_array = similar(array_of_expr)
# this doesn't work, i is undefined:
for i in range(1, length=length(array_of_expr))
result_array[i] = $(array_of_expr[i])
end
end
end
interpolate_1by1(test_input...)
Is there any way to make this work? I have tried the tactics in the cited SE answer, but did not have success.
you may unroll the loop at compile time:
#eval begin
function interpolate_1by1($(arglist...))
result_array = similar($array_of_expr)
$((quote
result_array[$i] = $(array_of_expr[i])
end for i in 1:length(array_of_expr))...)
return result_array
end
end
which after expansion is similar to
function interpolate_1by1($(arglist...))
result_array = similar($array_of_expr)
result_array[1] = $(array_of_expr[1])
result_array[2] = $(array_of_expr[2])
...
return result_array
end
What is wrong with my code? Do I have to declare x before using it?
function f(n::Int64, t::Int64)
A = ones(n,n)
for i=0:t
if i > 0
A[x,a] = rand()*A[x,a] + rand()
end
y = rand(1:n)
b = rand(1:n)
if i > 0
A[x,a] = rand()*A[x,a] + rand()*A[y,b]
end
x = y
a = min(b, rand(1:n))
end
return A
end
Here is the error thrown when trying to call f:
UndefVarError: x not defined
I think that the reason is more complex, as similar code in Python would work.
For example compare (Python):
>>> def f():
... for i in range(3):
... if i > 0:
... print(a)
... a = i
...
>>> f()
0
1
to (Julia):
julia> function f()
for i in 0:2
if i > 0
println(a)
end
a = i
end
end
f (generic function with 1 method)
julia> f()
ERROR: UndefVarError: a not defined
So what is the difference? As the Julia manual explains here you have:
for loops, while loops, and comprehensions have the following behavior: any new variables introduced in their body scopes are freshly allocated for each loop iteration, as if the loop body were surrounded by a let block
This means that in your code variables a and x as they are local to the for loop are freshly allocated in each iteration of the loop. Because of this the variable has to be assigned to before it is accessed inside the loop.
Therefore it is not needed to assign a value to x and a before the loop. It is enough to define them in scope outer to the loop (even without assigning of the value). For example like this:
julia> function f(n::Int64, t::Int64)
A = ones(n,n)
local x, a
for i=0:t
if i > 0
A[x,a] = rand()*A[x,a] + rand()
end
y = rand(1:n)
b = rand(1:n)
if i > 0
A[x,a] = rand()*A[x,a] + rand()*A[y,b]
end
x = y
a = min(b, rand(1:n))
end
return A
end
f (generic function with 1 method)
julia> f(1,1)
1×1 Array{Float64,2}:
0.94526289614139
Now it works because x and a are not freshly allocated in each iteration of the loop.
In my original toy example it would look like:
julia> function f()
local a
for i in 0:2
if i > 0
println(a)
end
a = i
end
end
f (generic function with 2 methods)
julia> f()
0
1
and you see that you get exactly what you had in Python.
In a different question on Stack Overflow the answer included the following function:
julia> function nzcols(b::SubArray{T,2,P,Tuple{UnitRange{Int64},UnitRange{Int64}}}) where {T,P<:SparseMatrixCSC}
return collect(i+1-start(b.indexes[2])
for i in b.indexes[2]
if b.parent.colptr[i]<b.parent.colptr[i+1] &&
inrange(b.parent.rowval[nzrange(b.parent,i)],b.indexes[1]))
end
nzcols (generic function with 3 methods)
And it was parsed without error. When adding a new-line before where clause for readability, an error suddenly appeared:
julia> function nzcols(b::SubArray{T,2,P,Tuple{UnitRange{Int64},UnitRange{Int64}}})
where {T,P<:SparseMatrixCSC}
return collect(i+1-start(b.indexes[2])
for i in b.indexes[2]
if b.parent.colptr[i]<b.parent.colptr[i+1] &&
inrange(b.parent.rowval[nzrange(b.parent,i)],b.indexes[1]))
end
ERROR: syntax: space before "{" not allowed in "where {"
Finally, when the parameter list parenthesis is moved to the where line, the error disappears again:
julia> function nzcols(b::SubArray{T,2,P,Tuple{UnitRange{Int64},UnitRange{Int64}}}
) where {T,P<:SparseMatrixCSC}
return collect(i+1-start(b.indexes[2])
for i in b.indexes[2]
if b.parent.colptr[i]<b.parent.colptr[i+1] &&
inrange(b.parent.rowval[nzrange(b.parent,i)],b.indexes[1]))
end
nzcols (generic function with 3 methods)
What is the logic behind this syntax and should it be fixed?
This is similar to many other syntaxes in the language; if the parser has a "complete" syntax at the end of a line, it'll use that and move on.
julia> parse("begin; 1 \n+ 2; end")
quote # none, line 1:
1 # none, line 2:
+2
end
julia> parse("begin; 1 +\n 2; end")
quote # none, line 1:
1 + 2
end
Note that this means you can still break the where clause onto a separate line, but the where itself needs to be on the same line as the end of the function.
I'm trying to understand how to work with this package for Julia.
Im using the following code (is an example from the package):
using HttpServer
function fibonacci(n)
if n == 1 return 1 end
if n == 2 return 1 end
prev = BigInt(1)
pprev = BigInt(1)
for i=3:n
curr = prev + pprev
pprev = prev
prev = curr
end
return prev
end
http = HttpHandler() do req::Request, res::Response
m = match(r"^/fibo/(\d+)/?$",req.resource)
if m == nothing
return Response(404)
end
number = BigInt(m.captures[1])
if number < 1 || number > 100_000
return Response(500)
end
return Response(string(fibonacci(number)))
end
http.events["error"] = (client, err) -> println(err)
http.events["listen"] = (port) -> println("Listening on $port...")
server = Server(http)
run(server, 8031)
And trying to access to the server with this link:
http://localhost:8031/fibo/100
But i get the next error:
MethodError(convert,(BigInt,"100"))
ERROR: MethodError: Cannotconvert an object of type
SubString{String} to an object of type BigInt
What im doing wrong?
I have problems to figure out what r"^/fibo/(\d+)/? does, maybe there is my problem...
You get this error because method BigInt(s::AbstractString) is deprecated and was remove in julia 0.5. Use number = parse(BigInt,m.captures[1]) instead.