Syntactic Goodies Julia

In this article I want to talk about the tasty and useful syntax buns Julia, which should sweeten the bitter share of the programmer.


Go!


image


Infix operators are ordinary functions.


, +, -, <, ==, in (&& || , .. - "" ), ( ). , .


, :


struct SetOfTwo{T}
     a::T
     b::T
     function SetOfTwo(a::A, b::B) where {A,B}
        if a != b
            T = promote_type(A, B)
            return new{T}(a, b)
        else
            throw(ArgumentError("Set elements must be distinct"))
        end
    end
end

:


Base.in(x, s::SetOfTwo) = x == s.a || x == s.b

Base.:(==)(s1::SetOfTwo, s2::SetOfTwo) = (s1.a in s2) && (s1.b in s2)

:


Base.:(==)(s1::SetOfTwo, s2::AbstractSet) = length(s2) == 2 && s1.a in s2 && s1.b in s2
Base.:(==)(s1::AbstractSet, s2::SetOfTwo) = s2 == s1

, , . , , :


julia> ⇒(a::Bool, b::Bool) = b || !a
⇒ (generic function with 1 method)

julia> struct  end

julia>  = ()

julia> 2 * 2 == 4 ⇒  isa 
true

!


: fn, , !fn — , .


julia> filter(!ismissing, [1, missing, missing, 3, 5, 8, missing])
4-element Array{Union{Missing, Int64},1}:
 1
 3
 5
 8


Julia - for , . for — for x in collection ... end. , . , iterate(collection[, state]), for :


for x in collection
    ...
end
    ⇓
let iter = iterate(collection)
while !isnothing(iter)
    x, state = iter
    ...
    iter = iterate(collection, state)
end

, iterate nothing, .


, , foreach ( ), collect ( ), in ( ) . , , . , , — , .


, , Base.Iterators . — , , , . , , .


Comprehensions


julia> [x for x in 1:3] # 
3-element Array{Int64,1}:
  1
  2
  3

julia> Float64[x^3 for x in 1:10 if iseven(x)] #   
5-element Array{Float64,1}:
    8.0
   64.0
  216.0
  512.0
 1000.0

julia> Dict(string(s) => length(s) for s in split("     ")) # 
Dict{String,Int64} with 6 entries:
  ""         => 1
  ""     => 5
  ""      => 4
  ""         => 1
  "" => 9
  ""       => 3

-, Python. Python , comprehension' , .


comprehension' — , :


julia> @btime sum([x for x in 1:10])
  38.467 ns (1 allocation: 160 bytes)
55

julia> @btime sum(x for x in 1:10)
  1.552 ns (0 allocations: 0 bytes)
55

, , , coll x for x in coll, — iterate. .



... :


julia> min(1, 2, 3)
1

julia> min([1, 2, 3])
ERROR: MethodError: no method matching min(::Array{Int64,1})
  ...

julia> min([1, 2, 3]...)
1

, . . — , :


julia> range_settings = Dict(:stop => 10, :step => 3)
Dict{Symbol,Int64} with 2 entries:
  :stop => 10
  :step => 3

julia> range(1, range_settings...)
ERROR: MethodError: no method matching range(::Int64, ::Pair{Symbol,Int64}, ::Pair{Symbol,Int64})
  ...

— , , . — , . , -:


julia> range_settings = Dict(:stop => 10, :step => 3)
Dict{Symbol,Int64} with 2 entries:
  :stop => 10
  :step => 3

julia> range(1; range_settings...)
1:3:10

julia> range_settings = [:stop => 10, :step => 3]
2-element Array{Pair{Symbol,Int64},1}:
 :stop => 10
 :step => 3

julia> range(1; range_settings...)
1:3:10

julia> range_settings = Set(range_settings)
Set{Pair{Symbol,Int64}} with 2 elements:
  :step => 3
  :stop => 10

julia> range(1; range_settings...)
1:3:10

— . , , , .


julia> range_settings = (stop = 10, step = 3)
(stop = 10, step = 3)

julia> range(1; range_settings...)
1:3:10


— , — , , . :


#  
function crossproduct1(p1::NTuple{3, Real}, p2::NTuple{3, Real})
    return p1[2]*p2[3] - p1[3]*p2[2], p1[3]*p2[1] - p1[1]*p2[3], p1[1]*p2[2] - p1[2]*p2[1]
end

#  
function crossproduct2((x1, y1, z1)::NTuple{3, Real}, (x2, y2, z2)::NTuple{3, Real})
    return y1 * z2 - y2 * z1, z1 * x2 - x1 * z2, x1 * y2 - y1 * x2
end

Broadcast


broadcasted-, , (loop fusion), ..


- ( / , / , , ) . , broadcast , , . — , "" , . , . "" broadcast(f, collection), , broadcast collection , .


, broadcast , . , , , .


julia> parse.(Int, ("3", "14", "15")).^(3, 2, 1)
(27, 196, 15)

julia> (x -> x / 5).(parse.(Float64, ["92", "65", "36"]))
3-element Array{Float64,1}:
 18.4
 13.0
  7.2

julia> parse.(Int, ("3", "14", "15")).^(3, 2, 1) .+ (x -> x / 5).(parse.(Float64, ["92", "65", "36"]))
3-element Array{Float64,1}:
  45.4
 209.0
  22.2

do


: do- , .


foo(args...) do x
    do_something
end


foo(x -> do_something, args...)

?


-, - map accumulate:


# 
map(x -> begin
            a, b, c = x[1], x[2], x[3]
            return a - (b + c) / 2, b - (a + c) / 2, c - (a + b) / 2
         end,
    [A, B, C])

# 
map([A, B, C]) do x
    a, b, c = x[1], x[2], x[3]
    return a - (b + c) / 2, b - (a + c) / 2, c - (a + b) / 2
end

-, with ... as ... Python. , open , :


open(f -> println(readline(f)), "myfile.txt", "r")

# 
open("myfile.txt", "r") do io
    firstline = readline(io)
    println(firstline)
end

, open , , , , :


function open(f::Function, args...)
    io = open(args...)
    try
        f(io)
    finally
        close(io)
    end
end

, — , do-. , , — , .


, , , .


All Articles