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)
#> 95.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
x + y
end
#> g (generic function with 1 method)
g(1, 2)
#> 2If 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)
V[i] += 1
end
return nothing
end
#> add_one! (generic function with 1 method)X = [i for i ∈ 1:3]
#> 3-element Vector{Int64}:
#> 1
#> 2
#> 3add_one!(X)
X
#> 3-element Vector{Int64}:
#> 2
#> 3
#> 45.4 Infix Function
1 + 2 + 3
#> 6
+(1,2,3)
#> 65.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)
#> 3String 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:3fib("abcd")
#> "abcdabcdabcd"Input non-defined argument type will error.
fib(1.5)
# This will error5.6 Anonymous Function
x -> x^2 + 2x - 1
#> #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
#> 95.7 Functional Programming
5.7.1 Map
📖 = [1.2, 2.7]
#> 2-element Vector{Float64}:
#> 1.2
#> 2.7map(round, 📖)
#> 2-element Vector{Float64}:
#> 1.0
#> 3.0map(x -> 2x + 1, 📖)
#> 2-element Vector{Float64}:
#> 3.4
#> 6.45.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.45.8 Multiple Return Values
A tuple is useful for return multiple values from a function.
function foo(a,b)
(add = a+b, prod = a*b)
end
#> foo (generic function with 1 method)x = foo(2,3)
#> (add = 5, prod = 6)
x
#> (add = 5, prod = 6)
x.add
#> 55.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:
(a,b,c) = 1:3
#> 1:3
# or
a, b, c = 1:3
#> 1:3
b
#> 2Destructuring assignment extracts each value from function into a variable:
a, b = foo(4, 5)
#> (add = 9, prod = 20)
a
#> 9
b
#> 20Underscore _
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 _
_, _, _, d = 1:10
#> 1:10
d
#> 4slurping ...
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:
a, b... = "hello"
#> "hello"
a
#> 'h': ASCII/Unicode U+0068 (category Ll: Letter, lowercase)
b
#> "ello"_, a, b... = 1:5
#> 1:5
a
#> 2
b
#> 3-element Vector{Int64}:
#> 3
#> 4
#> 55.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))
#> 2minmax(x, y) = (y < x) ? (y, x) : (x, y)
#> minmax (generic function with 1 method)
minmax(3, 2)
#> (2, 3)minmax(3, 2) |> gap
#> 1Notice 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
#> 75.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
#> 1Is 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
#> 1The 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.0becomes
(sqrt ∘ sum)([1, 3])
#> 2.0Pipe
1:10 |> sum |> sqrt
#> 7.416198487095663Vectorized Pipe
["a", "list", "of", "strings"] .|> uppercase
#> 4-element Vector{String}:
#> "A"
#> "LIST"
#> "OF"
#> "STRINGS"