-
Miroslav Kratochvil authoredMiroslav Kratochvil authored
- Expressions and types
- Types may have parameters (usually "contained type")
- Basic functionality and expectable stuff
- Control flow: Commands and code blocks
- Control flow: Conditional execution
- Control flow: Doing stuff many times
- Control flow: Doing stuff many times
- 💡 Structured cycles!
- Making new arrays with loops
- Control flow: subroutines (functions)
- 💡💡 Control flow: subroutine overloading (methods)
- 💡💡💡 Supertype hierarchy
- Function arguments
- Broadcasting over iterable things
- Advanced container types
Julia language primer
Expressions and types
Expressions and types You can discover types of stuff using typeof
.
Common types:
Bool
false, true
Char
'a', 'b', ...
String
"some random text"
Int
1, 0, -1, ...
Float64
1.1, 0, -1, ...
Types may have parameters (usually "contained type")
Vector{Int}
[1, 2, 5, 10]
Matrix{Float64}
[1.0 2.0; 2.0 1.0]
Tuple
(1, 2.0, "SomeLabel")
Set{Int}
Dict{Int,String}
(default parameter value is typically Any
)
Basic functionality and expectable stuff
-
Math:
+
,-
,*
,/
,^
, ... -
Logic:
==
,!=
,<
,>
,<=
,>=
,&&
,||
,!
, ... -
Assignment:
=
,+=
,-=
,*=
, ... -
I/O:
open
,println
,read
,readlines
, ... -
Arrays:
array[1]
,array[2:5]
,array[begin+1:end-1]
,size
,length
,cat
,vcat
,hcat
, ...
Most functions are overloaded to efficiently work with multiple types of data.
Functionality is easy to discover by just Tab
bing the definitions, also methods(...)
and methodswith(...)
.
Control flow: Commands and code blocks
Typically you write 1 command per 1 line.
Commands can be separated by semicolons, and grouped using code blocks:
begin
a = 10
b = 20; b += 20
a + b # implicit return!
end
Many constructions (cycles, function definitions) start the block
automatically, you only write end
.
Control flow: Conditional execution
- Traditional
if
:
if condition
actions
else # optional
actions # optional
end
- Shorter inline condition:
myfunction( index<=10 ? array[index] : default_value )
-
💡 Useful shell-like shortcuts:
a < 0 && (a = 0)
a > 10 && (a = 10)
isfinite(a) || @error "a is infinite, program will crash!"
Control flow: Doing stuff many times
Iteration count-based loop:
for var = iterable # , var2 = iterable2, ...
code(variable, variable2)
# ...
end
Syntax with in
instead of =
is also supported.
Examples:
for i = 1:10
@info "iterating!" i
end
for i = 1:10, j = 1:10
matrix[i,j] = i*j
end
Utilities: eachindex
, enumerate
Control flow: Doing stuff many times
Condition satisfaction-based loop:
while condition
do_something() # condition is true
end
# condition is false
Example:
number = 123519
digit_sum = 0
while number > 0
digit_sum += number % 10
number ÷= 10
end
@info "We've got results!" digit_sum
💡 Structured cycles!
Using functional-style loops is much less error-prone to indexing errors.
- Transform an array:
map(sqrt, [1,2,3,4,5])
map((x,y) -> (x^2 - exp(y)), [1,2,3], [-1,0,1])
- Summarize an array:
reduce(+, [1,2,3,4,5])
reduce((a,b) -> "$b $a", ["Use", "the Force", "Luke"])
reduce(*, [1 2 3; 4 5 6], dims=1)
Making new arrays with loops
julia> [i*10 + j for i = 1:3, j = 1:5]
3×5 Matrix{Int64}:
11 12 13 14 15
21 22 23 24 25
31 32 33 34 35
julia> join(sort([c for word in ["the result is 123", "what's happening?", "stuff"]
for c in word
if isletter(c)]))
"aaeeeffghhhiilnnpprssssttttuuw"
Control flow: subroutines (functions)
- Multi-line function definition
function combine(a,b)
return a + b
end
- "Mathematical" neater definition
combine(a,b) = a + b
-
💡 Definition with types specified (prevents errors, allows optimizations!)
function combine(a::Int, b::Int)::Int
return a + b
end
💡 💡 Control flow: subroutine overloading (methods)
- A method for combining integers
combine(a::Int, b::Int)::Int = a + b
- A method of the "same function" for combining strings
combine(a::String, b::String)::String = "$a and $b"
💡 💡 💡 Supertype hierarchy
Types possess a single supertype, which allows you to easily group
multiple types under e.g. Real
, Function
, Type
, Any
, ...
This creates groups of types that are useful for restricting your functions to work on the most reasonable subsets of inputs.
julia> Int
Int64
julia> Int.super
Signed
julia> Int.super.super
Integer
julia> Int.super.super.super
Real
julia> Int.super.super.super.super
Number
julia> Int.super.super.super.super.super
Any
(Upon calling the function, Julia picks the most specific available method.)
Function arguments
- Keyword arguments (can not be used for overloading)
function f(a, b=0; extra=0)
return a + b + extra
end
f(123, extra=321)
-
💡 Managing arguments en masse
euclidean(x; kwargs...) = sqrt.(sum(x.^2; kwargs...))
max_squared(args...) = maximum(args .^ 2)
Broadcasting over iterable things
- Broadcasting operators by prepending a dot
matrix[row, :] .+= vector1 .* vector2
- Broadcasting a function
sqrt.(1:10)
maximum.(eachcol(rand(100,100)))
x = [1,2,3,4]
x' .* x
broadcast(...)
.
Advanced container types
- Dictionaries (
Dict{KeyType, ValueType
) allow O(log n) indexing, great for lookups or keyed data structures. Contents may be typed for increased efficiency.
person = Dict("name" => "John", "surname" => "Foo", "age" => 30)
person["age"]
indexof(v::Vector) = Dict(v .=> eachindex(v))
-
💡 Sets are key-only containers (keys are unique)
julia> x=Set([1,2,3,2,1]);
julia> println(x)
Set([2, 3, 1])
julia> push!(x,5);
julia> push!(x,5);
julia> println(x)
Set([5, 2, 3, 1])