Table of Contents

為何使用julia?

背景簡介(開發、目前運作)

優勢

劣勢

遇到問題?

Google

The speed of julia

Julia 函式 (Functions)

在官方文件裡裡面,對於函式的定義是:”函式是一個將數組 (tuple) 引數 (argument) 對照到回傳值的物件”。也就是說,呼叫時是用數組的型態把引數傳遞給函式,函式內的運算結果再透過回傳值傳回。

我們可以透過函式的定義,將相同模式的動作或邏輯,抽象化提取出來成為可以重覆被呼叫使用的模塊。

可由以下方式建立函式:

function f(x, y)
    x + y # 函式預設回傳最後一個執行的結果
end

f(x, y) = x + y

也可使用匿名的方式建立(相當於matlab 的function handle: f = @(x, y) x + y )(More info):

f = (x, y) -> x + y

與 matlab 不同的是, julia 的函式都可以作為變數傳遞至其他函式:

函式的變數作用域 (Scope of Variable)

變數作用域 (Scope of Variable)指的是變數可以被"看到"的執行層面。 官方文件之詳細說明。 函式的變數作用域跟 for ... end 迴圈很類似,在 function ... end 區塊中才第一次被創建的變數,在區塊外面都不會被"看到"。

多重分派 (Multiple dispatch)

julia 的多重分派讓使用者只需遵循簡單的邏輯就能寫出高效率的程式碼。 julia 語言允許同 scope 下出現複數個同名函式;多重分派指的是根據輸入引數不同,自動分派到不同方法進行計算。

另一方面, 在單一分派的物件導向程式設計中(例如python matlab),我們會將函式(function)歸類到某個類別(class)底下的方法(method)。 以下是 python的範例程式碼:

# 定義型別
class Foo:
    def add(self, x):
        return str(x)

class Bar:
    def add(self, x):
        return int(x)

# 建立屬於某型別的物件
foo = Foo()
bar = Bar()

# 呼叫函式:
foo.add()
bar.add()

For more information, see this

在 matlab中,你必須寫例如像是

function abc(varargin)
if nargin > 1 
    ... 
else if nargin > 2 && ischar(varargin{1})
    ... 
    ... 
else if 
    ... 
else 
    ...
end

使得根據不同引述而進行的不同計算方法(例如 abc(x), abc(str, x), ...)能夠被實現。

從實例認識多重分派:

$$ \underbrace{切割}_{方法}\underbrace{木頭}_{物件} $$

建立一個🪵(木頭)的型別

建立一個其型別屬於🪵的物件實體:

創建一個方法🪓把木頭🪵砍半:

如果我想把木頭切成n等分?

🪓還可以拿來砍別的東西吧? 如果我想要把一個向量砍半的話...

methods看一個函式有哪些方法:

從 julia 內建的乘法看多重分派

實數乘法:

虛數乘法:

矩陣乘法:

$ \begin{pmatrix} 1 & 2 \\ 3 & 4 \end{pmatrix} \begin{pmatrix} 3 & 1 \\ 0 & 2 \end{pmatrix} = \begin{pmatrix} 3 & 5 \\ 9 & 11 \end{pmatrix} $

字串相乘?

擴充乘法

一般來說, 3*"Hello" 是會報錯的,因為不存在方法支援整數(Int)與字串(String)的相乘:

julia:repl
ERROR: MethodError: no method matching *(::Int64, ::String)

julia 的操作運算子也都是函式, 例如, 3*2 其實也可以寫成 *(3,2)。 julia 內建的函式都放在 Base 下面。 利用多重分派, 我們可以新增乘法符號的新方法, 使得 3*"Hello" 得到 "HHHeeellllllooo"

常用型別系統

抽象型別(Abstract type)

💡Hint: 用supertypesubtypes 可以看一個型別的父型別和子型別們

符號、字串與字元

在 julia 中,想要在字串中表達雙引號(")有兩種方式。第一種是使用跳脫字元(Escape Character),例如:

第二種是使用三連雙引號(triple double quotes)

作為變數,兩者是相同的

慣例

是否照慣例做並不影響執行結果。但是,遵循基本慣例可以讓我們光靠閱讀程式碼的階段就可以大致理解程式碼在做什麼;不遵循慣例會造成不必要的麻煩,對所有人都沒好處。

範例 – 結尾有驚嘆號的函式

結尾有驚嘆號的函式提醒我們某一個輸入變數會直接被改變。

剛剛的🪓函式因為會改變輸入物件🪵本身。故按照慣例,命名應該要加驚嘆號才是!

function 🪓!(...)
    ...
end

範例 – 命名規則

DataFrame (型別或建構子) and DataFrames (套件)

說明:

df = DataFrame(:Time => t, :Y => Y)

是透過 DataFrame 型別的其中一個建構子(constructor) DataFrame(pairs::Pair...; makeunique::Bool=false, copycols::Bool=true)所建構。methods(DataFrame) 可以查到DataFrame所有的建構子。我們可以把建構子想成與型別名稱相同的函式。

舉一反三

String(:X) 是透過 String 型別下的一個接受符號(Symbol)類別 :X 為輸入的建構子,建構字串"X"這個物件。

我們常常可以用型別建構子將物件"轉換"成我們想要的類型。

容器

陣列 (Array)

⚠️ 注意:

⚠️ 注意:陣列(Array) 是可變的(mutable)。這時候 v1 = v 相當於將新變數名(v1)指向舊變數(v)。如果想要複製變數,請用 copy (e.g., v1 = copy(v))。

集合 (Collection)

數組 (Tuple)

配對(Pair)

Pair 型別是用來建立 key / value 兩種物件對應的型別,Pair 也是不可變的 (immutable)。Pair 的建立可以透過建構子或是 key=>value 語法建立。

字典(Dict)

可以透過數組或配對來建立字典

新增條目

關於字典的常用方法

集合(Set)

聯集

關於Set的常用方法

條件與迴圈

條件

兩個條件判斷:

if 條件式
    運算式
else
    運算式
end

多個條件判斷:

if 條件式
    運算式
elseif 條件式
    運算式
else
    運算式
end

比較特別的是 if ... end 本身會回傳值

迴圈

預分配(preallocate)

Julia 的預分配邏輯跟 matlab 或其他程式語言相似:在迴圈外先定義好輸出向量,再將向量丟進去運算會大幅減少對記憶體進行操作的時間。

julia 有簡單好用的 push!,不用預分配也有不錯的速度:

操作子

宣告 x 和 y,並將值均指定為 3。

點運算

小結

相較於MATLAB,Julia在使用上更須遵守規則,但也更自由

例如,

作業

  1. 寫一個drop函式,包含兩個方法:
  1. 寫一個lastnan!函式,包含2個方法: