In [1]:
function doubler(x)
return 2x # okay to have literal * variable without *
end
Out[1]:
In [2]:
doubler(2), doubler(6)
Out[2]:
But we can also omit some syntax in the interest of making things shorter:
In [3]:
function tripler(x)
3x # implicit return
end
Out[3]:
In [4]:
tripler(3.5), tripler(2)
Out[4]:
In [5]:
halver(x) = x//2
Out[5]:
In [6]:
halver(5), halver(4)
Out[6]:
And finally, for the functional crowd:
In [7]:
firstelem = x -> x[1]
Out[7]:
In [8]:
firstelem("tester")
Out[8]:
In Python, particularly NumPy, we don't default to copies when passing function arguments. Julia works the same way.
In [9]:
A = rand(5, 5)
Out[9]:
In [10]:
function zerodiag!(x)
for i in 1:maximum(size(x)) # it's okay (and fast!) to write a loop
x[i, i] = 0
end
return x
end
Out[10]:
In [11]:
B = zerodiag!(A)
Out[11]:
In [12]:
B, A
Out[12]:
It can be useful to package multiple inputs to a function into an interable (cf. *args).
In [13]:
function parser(var, val, rest...)
println("variable name: $var")
println("variable value: $val")
println(rest)
end
Out[13]:
In [14]:
parser(:x, 5, 7, 8, "foo")
Conversely, we'd like to be able to "splat" a collection into separate arguments for passing to a function:
In [15]:
function randlike(A)
sizetup = size(A)
return rand(sizetup...)
end
Out[15]:
In [16]:
randlike(ones(5))
Out[16]:
In [17]:
function Lpnorm(x, p=2)
return sum(x.^p)^(1/p)
end
Out[17]:
Note two methods! We'll come back to this.
In [18]:
aa = rand(10)
norm(aa), Lpnorm(aa), Lpnorm(aa, 1)
Out[18]:
We can also use keywords:
In [19]:
function makecircle(x, y, radius=1; color="black", fill=color) # later kwargs can use values of previous
println("$color circle of radius $radius centered at ($x, $y) with $fill border")
end
Out[19]:
In [20]:
makecircle(0, 0)
In [21]:
makecircle(0, 0, 5)
In [22]:
makecircle(0, 0, color="blue") # no semicolon needed
As we'll see, Julia is less flexible about keyword vs. positional arguments because this is required to keep multiple dispatch sane.
Each case above could basically work in Python. In fact, we can do something very like duck typing:
In [23]:
lastelem(x) = x[end]
Out[23]:
In [24]:
lastelem(1:5), lastelem([2, 4, 6]), lastelem("foobar")
Out[24]:
But what if we needed some special casing:
We'd like to be able to solve a few problems:
doubler handle multiple cases, depending on inputdoubler if it's not our functionIn Python and other object-oriented languages, this is solved with classes. Classes dispatch on instances (i.e., based on self). In Julia, we'll solve this problem with multiple dispatch.
First, however, we need to understand how types work in Julia.
In [ ]: