Creating Functions
function 的定義:an object that maps a tuple of arguments values to a return value
julia> function greet()
println("hello world")
end
greet (generic function with 1 method)
julia> greet()
hello world
julia> function calculator(x, y, operation)
if operation == "+"
x+y
elseif operation == "-"
x-y
elseif operation == "*"
x*y
elseif operation == "/"
x/y
else
println("Incorrect operation")
return 0
end
end
calculator (generic function with 1 method)
julia> println(calculator(10,20, "+"))
30
julia> println(calculator(10,20, "*"))
200
如果在 function 名稱最後面看到 ! 這個符號,這是 julia 的命名習慣,這表示這個 function 會修改 input 的參數資料內容,例如 push!
julia> push!([1,2,3], 4)
4-element Array{Int64,1}:
1
2
3
4
Function Argurments
通常參數是以 pass by value 或是 pass by reference 的方式處理,但 julia 是使用 pass by sharing 的方式。
pass by value: 傳入 function 的參數,會複製數值,這表示該變數會產生 2 copies
pass by reference: function 的參數,會使用該變數的 reference,該變數只有 1 copy
pass by sharing: 傳入 function 的變數,不會被複製。參數本身只是一個新的 binding,參考到原本變數的值。這也很像是 pass by value,只是那個 value 是 object reference。
ref: 深入探討 JavaScript 中的參數傳遞:call by value 還是 reference?
以 function 內對參數重新賦值,外面的變數如果也會改變,就是 pass by reference。如果不會改變就是 pass by value,在 pass by value 的條件下,如果可以透過變數,修改 function 外面的變數的值,就是 pass by sharing。
return keyword
return 用來結束 function 執行,julia 的 function 可使用或不使用 return,如果 function 沒有 return,就表示會回傳最後一個 statement 的運算結果。
julia> function add_without_return(x,y)
x+y
end
add_without_return (generic function with 1 method)
julia> function add_using_return(x,y)
return x+y
end
add_using_return (generic function with 1 method)
julia> add_without_return(20,30) == add_using_return(20,30)
true
arguments
傳入的參數,可以不指定資料型別,也可以限制資料型別。限制資料型別,可讓 compiler 介入並最佳化編譯結果。
function say_hello(name)
println("hello $name")
end
say_hello("world")
function say_hello(name::String)
println("hello $name")
end
say_hello("world")
function 可以沒有任何參數
julia> function does_nothing
end
does_nothing (generic function with 0 methods)
varargs 是 variable arguments,不定長度的參數,julia 是使用 ...
傳入三個參數,第一個獨立,第2,3 個參數,在 function 裡面是對應為 y...
,所以 y 是 tuple
julia> function letsplay(x,y...)
println(x)
println(y)
end
letsplay (generic function with 1 method)
julia> letsplay("cricket","hockey","tennis")
cricket
("hockey", "tennis")
傳入 function 的變數,可以在定義 function 前,就先宣告該變數
x = (1,2,3,4,5)
y = (6,7,8)
function numbers(a...)
println("the arguments x are -> ", x)
println("the arguments a are -> ", a)
end
numbers(y)
# the arguments x are -> (1, 2, 3, 4, 5)
# the arguments a are -> ((6, 7, 8),)
x = [1,2,3,4,5]
y = [6,7,8]
numbers(y)
# the arguments x are -> [1, 2, 3, 4, 5]
# the arguments a are -> ([6, 7, 8],)
optional arguments
function 中有些參數已經有預設值,呼叫該 function 就不需要傳入該參數
function f(x, y=4, z=10)
x+y+z
end
f(10)
# 24
variable scope
julia 有兩個主要的 scope: global, local
module 內或是 REPL 內的變數,通常是 global scope。loops, functions, macros, try-catch-finally block 裡面的變數是 local scope。
如果刻意加上 global,可讓變數變成 global scope
julia> for i=1:5
global hello
hello = i
end
julia> hello
5
lexical scoping: funtion 的 scope 不會繼承 caller's scope,而是由 function 定義的時候開始。例如 module 內定義了 name 變數,後面又定義了另一個 name,當呼叫 module 內的 method,使用的 name 變數,是一開始在 module 內定義的 name。
julia> module Utility
name = "Julia"
tell_name() = name
end
Main.Utility
julia> name = "Python"
"Python"
julia> Utility.tell_name()
"Julia"
julia 將 local scope 分為 soft 及 hard local scope,function 裡面是 hard local scope。
nested functions
*
如果是兩個整數,就是整數相加,如果是兩個字串,則是將字串連接在一起
julia> function outer(value_a)
function inner(value_b)
return value_a * value_b
end
end
outer (generic function with 1 method)
# 回傳一個 function
julia> result = outer(10)
(::getfield(Main, Symbol("#inner#3")){Int64}) (generic function with 1 method)
julia> typeof(result)
getfield(Main, Symbol("#inner#3")){Int64}
julia> result(10)
100
julia> result = outer("learning ")
(::getfield(Main, Symbol("#inner#3")){String}) (generic function with 1 method)
julia> result("Julia")
"learning Julia"
Anonymous Functions
也可稱為 lambda functions
語法:f -> 2f
map() 的第一個參數,需要傳入一個 function,可使用 anonymous function
julia> map(f -> 2f, [2, 3])
2-element Array{Int64,1}:
4
6
julia> map(f -> 2f, [2 3])
1×2 Array{Int64,2}:
4 6
julia> map((f,g) -> 2f + 2g, [2,3], [3,4])
2-element Array{Int64,1}:
10
14
Multiple Dispatch
dispatch 就是 to send 的意思,也就是 send a message to a listener,或是 call to a function
dispatch 有以下形式
static dispatch
在 compile time 定義 dispatch order,在執行程式前,就已經知道所有資料型別。compiler 能夠對所有可能的資料型別的組合,都產生對應的程式碼,並預先知道什麼時候在哪裡被使用。這是程式語言中最常見的形式。
可用 funct() 或是 x.functiont() 呼叫 function / method,每次呼叫時都是固定不變的。
dynamic dispatch
runtime 定義 dispatch order。compiler 會產生所有 functions 的 lookup table,在 runtime 決定要呼叫哪一個 function。
例如有 classA, classB 都有 foo() function,runtime 時,兩個 class 都會被檢查到有 foo(),可能或呼叫 classA.foo() 或是 classB.foo() 任一個 function
multiple dispatch
dispatch order 跟 function name 以及 argument types 有關,runtime 決定使用的 signature of the function 以及 actual implementation。
classA 有 foo(int) 以及 foo(char) ,當呼叫 classA.foo(x) 時,在 runtime 會檢查 classA 及 x,然後決定要使用哪一個 function
julia 使用 multiple dispatch
Understanding methods
尋找適當的函數,同時會檢查參數的資料型別
function add_numbers(num1::Int64, num2::Int64)
return num1 + num2
end
add_numbers(10,20)
add_numbers(10.0,20.0)
# ERROR: MethodError: no method matching add_numbers(::Float64, ::Float64)
function add_numbers(num1::Float64, num2::Float64)
return num1+num2
end
julia> methods(add_numbers)
# 2 methods for generic function "add_numbers":
[1] add_numbers(num1::Float64, num2::Float64) in Main at REPL[36]:2
[2] add_numbers(num1::Int64, num2::Int64) in Main at REPL[33]:2
如果要用一個 methd 同時支援多種資料型別,可以用類似 python 的做法,不指定參數的資料型別
function add_without_types(num1,num2)
return num1+num2
end
add_without_types(10.0,20)
add_without_types(10,20.0)
Recursion
遞迴: 重複呼叫自己的 function
function generate_fibonacci(n::Int64)
if n < 2
return 1
else
return generate_fibonacci(n-1) + generate_fibonacci(n-2)
end
end
# 另一種更簡單的寫法
generate_fibonacci(n) = n < 2 ? n : generate_fibonacci(n - 1) + generate_fibonacci(n - 2)
Built-in Functions
julia 的 base library 提供很多內建的 functions
workspace()
只能在 REPL 使用,可以將目前 REPL 的所有資料清空
note: 這個function 在 julia 1.0 已經不提供了
ref: https://stackoverflow.com/questions/51872039/which-is-the-alternative-to-workspace-in-julia-1-0
typeof()
查詢參數的資料型別
methods()
查詢所有提供該 method 的 functions
julia> methods(+) # 163 methods for generic function "+": [1] +(x::Bool, z::Complex{Bool}) in Base at complex.jl:277 [2] +(x::Bool, y::Bool) in Base at bool.jl:104 ...
readline(), readlines()
由 STDIN 讀取 user input,如果加上參數,則是自檔案讀取資料
julia> name = readline() julia "julia" julia> readlines("file.txt") 43-element Array{String,1}: ...
enumerate()
用來 iterate over a collection
julia> fruits = ["apple", "orange", "banana"] 3-element Array{String,1}: "apple" "orange" "banana" julia> for (index,fruit) in enumerate(fruits) println("$index -> $fruit") end 1 -> apple 2 -> orange 3 -> banana
parse()
用來 parse a string,轉換為 number
parse(type, str; base)
base 是代表幾進位
julia> parse(Int, "2") 2 julia> parse(Float64, "2.2") 2.2 julia> parse(Int, "1234", base = 5) 194
沒有留言:
張貼留言