2019年5月20日

Types and Dispatch in juila

julia 同樣也有 type system 處理 Types, Data Types,可識別 integer, string, float, Boolean。

Type system

types 是什麼?
1
1.1
'j'
"julia"

這些資料都可以直接識別出差異,分別是 integer, float, char, string。但需要一個方法讓電腦能夠識別這些資料型別。

static type vs dynamic type

有兩種方法可告訴 interpreter 資料型別是什麼

static type: 直接標記出資料型別,例如 C, C++, Java

dynamic type: interpreter 在 runitme 自動判斷資料型別,例如 Perl, Python, Ruby。雖然不指定,但內部還是會將該資料,標記為某一個資料型別

julia 同時有 static type 及 dynamic type 的功能。如果使用 static type,會讓程式運作地比較快。

Type annotations

討論 type declaration 及 conversion

:: Int64 就是將變數定義為 Int64 這個資料型別

julia> function cube(number::Int64)
        return number ^ 3
       end
cube (generic function with 1 method)

julia> cube(3)
27

實際上 :: 是個 operator,也很類似 python 的 isinstance()

julia> 2::Int64
2

julia> 2::Float64
ERROR: TypeError: in typeassert, expected Float64, got Int64

  • typeof(): type of data
  • typemax(): 該 type 可支援的最大 value
  • typemin(): 該 type 可支援的最小 value
  • bitstring(): 二進位的位元字串

  • Integer type 會根據使用的機器不同,可能是 Int8, Int16, Int32, Int64, or Int128 其中一種

    julia> typeof(1)
    Int64
    
    julia> typemax(Int64)
    9223372036854775807
    
    julia> typemin(Int64)
    -9223372036854775808
  • Float type 在 64bits 機器,是 Float64

    julia> typeof(1.1)
    Float64
    
    julia> typemax(Float64)
    Inf
    
    julia> typemin(Float64)
    -Inf
  • Char type

  • String type

  • Bool type


isa(x, type) -> Bool 判斷 x 資料型別是否為 type

julia> isa(5, Int64)
true

julia> isa(5.5, Float64)
true

type conversions

convert(type, x) 可將 x 轉換資料型別為 type

julia> convert(Float64, 10)
10.0

julia> convert(Int64, 128.0)
128

julia> convert(Int64, 128.3)
ERROR: InexactError: Int64(Int64, 128.3)
Stacktrace:
 [1] Type at ./float.jl:700 [inlined]
 [2] convert(::Type{Int64}, ::Float64) at ./number.jl:7
 [3] top-level scope at none:0

rounding: ceil, floor, round

julia> ceil(Int, 3.4)
4

julia> floor(Int, 3.4)
3

julia> round(Int, 3.4)
3

julia> round(Int, 3.6)
4

subtypes and supertypes

Number 是 Any 的 subtype,Any 是 Number 的 supertype

                      Any
                       |
     ---------------------------------------------
     Number                          AbstractString
        |                                   |
----------------                            |
Complex       Real                          |
                                            |
                                            |
         ----------------------------------------------------------
        |           |           |                     |            |
UTF8String    UTF16String     DirectIndexString   RepString    RopeString

Any 是所有資料型別的起點

julia> supertype(Number)
Any

julia> supertype(Any)
Any

julia> typeof(Any)
DataType

julia> subtypes(Number)
2-element Array{Any,1}:
 Complex
 Real

recursive 找出所有子類別

julia> function check_all_subtypes(T, space=0)
                  println("\t" ^ space, T)
                  for t in subtypes(T)
                      if t!= Any
                      check_all_subtypes(t, space+1)
                  end
              end
              end
check_all_subtypes (generic function with 2 methods)

julia> check_all_subtypes(Number)
Number
    Complex
    Real
        AbstractFloat
            BigFloat
            Float16
            Float32
            Float64
        AbstractIrrational
            Irrational
        Integer
            Bool
            Signed
                BigInt
                Int128
                Int16
                Int32
                Int64
                Int8
            Unsigned
                UInt128
                UInt16
                UInt32
                UInt64
                UInt8
        Rational

User-defined and composite data types

可自訂資料型別: use abstract|primitive type, struct, mutable struct for type definitions

ref: crazy idea: change the type keyword

julia> struct Person
           name::String
           age::Int64
       end

julia> typeof(Person)
DataType

julia> a = Person("Name", 10)
Person("Name", 10)

julia> typeof(a)
Person

julia> a.name
"Name"

julia> a.name = "name2"
ERROR: type Person is immutable

檢查自訂資料型別的層級

julia> supertype(Person)
Any

julia> subtypes(Person)
0-element Array{Type,1}

julia> fieldnames(Person)
(:name, :age)

julia> typeof(:name)
Symbol

composite types

剛剛的 Person 資料無法修改,使用 mutable struct 就可以變成可修改的資料型別

julia> mutable struct Point
           x :: Int64
           y :: Int64
           z :: Int64
       end

julia> p = Point(1,2,3)
Point(1, 2, 3)

julia> p.x=10
10

julia> p
Point(10, 2, 3)

Inner constructor

剛剛的 struct,可在 constructor 中,增加資料的檢查,確認新的物件符合資料型別設計的條件

julia> struct Family
          num_members :: Int64
          members :: Array{String, 1}

          # inner constructor in play
          Family(num_members, members) = num_members != length(members) ? error("Mismatch!!") : new(num_members, members)
       end

julia> f1 = Family(1, ["husband", "wife"])
ERROR: Mismatch!!
Stacktrace:
 [1] error(::String) at ./error.jl:33
 [2] Family(::Int64, ::Array{String,1}) at ./REPL[14]:6
 [3] top-level scope at none:0

julia> f2 = Family(2, ["husband", "wife"])
Family(2, ["husband", "wife"])

Modules and interfaces

julia 的 namespaces,可讓我們建立 top-level global variable,但又不會在所有程式中互相衝突。

module SampleModule
..
..
end
julia> module MyModule
                  foo=10
                  bar=20
                  function baz()
                      "baz"
                  end
                  function qux()
                      "qux"
                  end
                  export foo, baz
                  end
Main.MyModule

julia> MyModule.bar
20

using MyModule 跟 import MyModule 的差異

  • using MyModule,會將所有 exported functions 都帶入目前的 scope,等於是宣告 MyModule.foo,可以這樣使用 MyModule:foo
  • import MyModule,將 functions 匯入目前的 scope,只能取得 exported functions/variables,就無法使用 foo

Including files in modules

當 module, package 分散在多個檔案中,使用 include 彙整

# 按下 ; 進入 shell
# transformations.jl 是獨立的檔案
shell> cat transformations.jl
function say_hello(name:: String)
    "hello, $name"
end
julia> include("transformations.jl")
say_hello (generic function with 1 method)

julia> say_hello("rahul")
"hello, rahul"

Module file paths

通常用 using SomeModule 時,julia 會尋找預設 module 路徑

可用 push! 增加 library 路徑,或是設定環境變數 JULIA_LOAD_PATH

julia> push!(LOAD_PATH, "~/Downloads/Module/")
4-element Array{String,1}:
 "@"
 "@v#.#"
 "@stdlib"
 "~/Downloads/Module/"

module precompilation

在使用某個 module 時,會先花一些時間進行編譯,如果有編譯完成的,才會直接匯入

目前 1.0 版,所有 modules 都是enable precompilation

Samplecode.jl

module Samplecode

export sum_of_numbers

sum_of_numbers = 0
for num in 1:10000
    global sum_of_numbers += num
end

end
julia> push!(LOAD_PATH, "~/path/")
4-element Array{String,1}:
 "@"
 "@v#.#"
 "@stdlib"
 "~/path/"

julia> @time using Samplecode
[ Info: Precompiling Samplecode [top-level]
  1.343508 seconds (1.13 M allocations: 55.605 MiB, 0.38% gc time)

julia> @time using Samplecode
  0.000552 seconds (782 allocations: 42.547 KiB)

multiple dispatch

julia> struct Coordinate{T}
                  x::T
                  y::T
                  z::T
              end

julia> function calc_sum(value::Coordinate{Int64})
                  value.x + value.y + value.z
              end
calc_sum (generic function with 1 method)

julia> function calc_sum(value::Coordinate{Float64})
                         value.x + value.y + value.z
              end
calc_sum (generic function with 2 methods)

julia> methods(calc_sum)
# 2 methods for generic function "calc_sum":
[1] calc_sum(value::Coordinate{Float64}) in Main at REPL[6]:2
[2] calc_sum(value::Coordinate{Int64}) in Main at REPL[5]:2

julia> calc_sum(Coordinate(1,2,3))
6

julia> calc_sum(Coordinate(1.0,2.0,3.0))
6.0

References

Learning Julia

沒有留言:

張貼留言