function sayhi(name)
println("Hi $name, it's great to see you!")
end
#> sayhi (generic function with 1 method)
5 Function
See Function
5.1 Declare a Function
sayhi("😸")
#> Hi 😸, it's great to see you!
Single line
square(x) = x^2
#> square (generic function with 1 method)
square(3)
#> 9
5.2 Return Keyword
Like R
the last line in the body of function is returned.
If you want to return prematurely use return
keyword.
function g(x,y)
return x * y
+ y
x end
#> g (generic function with 1 method)
g(1, 2)
#> 2
If function has no return value (called for side-effect), return nothing
by convention.
5.3 Side Effect !
Function that modifys argument in-place are suffix with !
.
function add_one!(V)
for i in 1:length(V)
+= 1
V[i] end
return nothing
end
#> add_one! (generic function with 1 method)
= [i for i ∈ 1:3]
X #> 3-element Vector{Int64}:
#> 1
#> 2
#> 3
add_one!(X)
X#> 3-element Vector{Int64}:
#> 2
#> 3
#> 4
5.4 Infix Function
1 + 2 + 3
#> 6
+(1,2,3)
#> 6
5.5 Argument-type Declaration
Integer
method
fib(n::Integer) = n ≤ 2 ? one(n) : fib(n-1) + fib(n-2)
#> fib (generic function with 1 method)
fib(4)
#> 3
String
method
I declare x
as a super-type AbstractString
to include all possible string type.
fib(x::AbstractString) = x^fib(length(x))
#> fib (generic function with 2 methods)
Now fib
has 2 methods
methods(fib)
#> # 2 methods for generic function "fib":
#> [1] fib(n::Integer) in Main at none:3
#> [2] fib(x::AbstractString) in Main at none:3
fib("abcd")
#> "abcdabcdabcd"
Input non-defined argument type will error.
fib(1.5)
# This will error
5.6 Anonymous Function
-> x^2 + 2x - 1
x #> #45 (generic function with 1 method)
The primary use for anonymous functions is passing them to functions which take other functions as arguments.
Useful in map(f, collection)
map(x -> x^2, 1:3)
#> 3-element Vector{Int64}:
#> 1
#> 4
#> 9
5.7 Functional Programming
5.7.1 Map
= [1.2, 2.7]
📖 #> 2-element Vector{Float64}:
#> 1.2
#> 2.7
map(round, 📖)
#> 2-element Vector{Float64}:
#> 1.0
#> 3.0
map(x -> 2x + 1, 📖)
#> 2-element Vector{Float64}:
#> 3.4
#> 6.4
5.7.2 Broadcast
Shorter way is to broadcast
a function.
h(x) = 2x + 1
#> h (generic function with 1 method)
h.(📖)
#> 2-element Vector{Float64}:
#> 3.4
#> 6.4
5.8 Multiple Return Values
A tuple is useful for return multiple values from a function.
function foo(a,b)
= a+b, prod = a*b)
(add end
#> foo (generic function with 1 method)
= foo(2,3)
x #> (add = 5, prod = 6)
x#> (add = 5, prod = 6)
x.add#> 5
5.9 Destructuring Assignment
A comma-separated list of variables (optionally wrapped in parentheses) can appear on the left side of an assignment: the value on the right side is destructured by iterating over and assigning to each variable in turn:
= 1:3
(a,b,c) #> 1:3
# or
= 1:3
a, b, c #> 1:3
b#> 2
Destructuring assignment extracts each value from function into a variable:
= foo(4, 5)
a, b #> (add = 9, prod = 20)
a#> 9
b#> 20
Underscore _
If only a subset of the elements of the iterator are required, a common convention is to assign ignored elements to a variable consisting of only underscores _
= 1:10
_, _, _, d #> 1:10
d#> 4
slurping ...
If the last symbol in the assignment list is suffixed by ...
(known as slurping), then it will be assigned a collection or lazy iterator of the remaining elements of the right-hand side iterator:
... = "hello"
a, b#> "hello"
a#> 'h': ASCII/Unicode U+0068 (category Ll: Letter, lowercase)
b#> "ello"
... = 1:5
_, a, b#> 1:5
a#> 2
b#> 3-element Vector{Int64}:
#> 3
#> 4
#> 5
5.10 Argument destructuring
If a function argument name is written as a tuple (e.g. (x, y)) instead of just a symbol, then an assignment (x, y) = argument will be inserted for you:
gap((min, max)) = max - min
#> gap (generic function with 1 method)
gap((1, 3))
#> 2
minmax(x, y) = (y < x) ? (y, x) : (x, y)
#> minmax (generic function with 1 method)
minmax(3, 2)
#> (2, 3)
minmax(3, 2) |> gap
#> 1
Notice the |>
pipe operator.
For anonymous functions, destructuring a single tuple requires an extra comma:
map( ((x,y),) -> x + y, [(1,2), (3,4)] )
#> 2-element Vector{Int64}:
#> 3
#> 7
5.11 Do Block
From this map(long_f, collection)
map(x->begin
if x < 0 && iseven(x)
return 0
elseif x == 0
return 1
else
return x
end
end,
-1, 0, 1])
[#> 3-element Vector{Int64}:
#> -1
#> 1
#> 1
Is equivalent to map(collection) do long_f
map([-1, 0, 1]) do x
if x < 0 && iseven(x)
return 0
elseif x == 0
return 1
else
return x
end
end
#> 3-element Vector{Int64}:
#> -1
#> 1
#> 1
The do x
syntax creates an anonymous function with argument x
and passes it as the first argument to map
.
Do
blog might help reader to read from left to right.
5.12 Compose & Piping
(f ∘ g)(args...)
is the same as f(g(args...))
composition operator is ∘
\circ<tab>
sqrt(sum([1, 3]))
#> 2.0
becomes
∘ sum)([1, 3])
(sqrt #> 2.0
Pipe
1:10 |> sum |> sqrt
#> 7.416198487095663
Vectorized Pipe
"a", "list", "of", "strings"] .|> uppercase
[#> 4-element Vector{String}:
#> "A"
#> "LIST"
#> "OF"
#> "STRINGS"