𝖄𝕺🌎𝕿𝕽𝕺¥

𝖄𝕺🌎𝕿𝕽𝕺¥

𝕴 𝖉𝖔 𝖒𝖆𝖌𝖎𝖈
github

Haskell筆記二

類型#

特性#

強(strong)類型

靜態(static)

可以通過自動推導(automatically inferred)得出

基本類型#

Char
Bool
Int 常用 定長(fixed-width)整數 一般32/64位寬
Integer 不常用 不定長
Double 常用 浮點數
Float 不常用 計算慢
Prelude> :type 'a'
'a' :: Char

Prelude> 'a'            -- 自動推導
'a'

::符號
Prelude> 'a' :: Char    -- 显式簽名
'a'

調用函數#

Prelude> odd 3
True

Prelude> compare 2 3
LT
e.g. LT EQ GT

Prelude> (compare 2 3) == LT
True

Prelude> compare (sqrt 3) (sqrt 6)  -- 此處括號不可去
LT

複合數據類型:列表和元組#

不同?#

列表可以任意長,且只能包含類型相同的值。

元組的長度是固定的,但可以包含不同類型的值。

可遞歸性#

[[Int]] 是一個包含 [Int] 類型值的列表,而 [Int] 又是一個包含 Int 類型值的列表即用 Int 類型替換了類型變量 a 。

列表 [] 及 head, tail, last ; take, drop#

head 取第一個元素, tail 取除第一個外所有
last 取最後一個元素

Prelude> head [1, 2, 3, 4]
1

Prelude> head []
*** Exception: Prelude.head: empty list

Prelude> tail "list"
"ist"
ghci> last [1,2,3]
3
Prelude> take 2 [1, 2, 3, 4, 5]
[1,2]
Prelude> drop 2 [1, 2, 3, 4, 5]
[3,4,5]
Prelude> drop 4 [1, 2]
[]
Prelude> drop (-1) "foo"    --第一個參數小於或等於 0時, drop 函數返回整個輸入列表
"foo"

元組 () 及 fst, snd#

大小至少為 2

元組的類型由它所包含元素的數量、位置和類型決定

Prelude> :type (True, "hello")
(True, "hello") :: (Bool, [Char])
Prelude> (4, ['a', 'm'], (16, True))
(4,"am",(16,True))
Prelude> :t ()
() :: ()
Prelude> fst (1, 'a')
1

Prelude> snd (1, 'a')
'a'

元組使用場景 e.g.#

  • 如果一個函數需要返回多個值,那麼可以將這些值都包裝到一個元組中,然後返回元組作為函數的值。

  • 當需要使用定長容器,但又沒有必要使用自定義類型的時候,就可以使用元組來對值進行包裝。

利用括號將表達式傳給函數#

a b c d 等於 (((a b) c) d)

純度#

帶副作用的函數稱為 不純(impure)函數 ,而將不帶副作用的函數稱為 純(pure)函數

副作用即函數中全局變量可修改如取決於某一時刻的值,本質上是函數的一種不可見的(invisible)輸入或輸出。Haskell 的函數在默認情況下都是無副作用的:函數的結果只取決於顯式傳入的參數。

不純函數的類型簽名都以 IO 開頭,以下為檢測 e.g.:

Prelude> :type readFile
readFile :: FilePath -> IO String
-- 不純函數的類型簽名都以 IO 開頭

加載.hs 文件#

ghci 中通過:load

變量#

一旦變量綁定了(也即是,關聯起)某個表達式,那麼這個變量的值就不會改變。如.hs 文件中就不行,但 ghci 命令行裡可以。

e.g. [Assign.hs]

條件求值#

不同分支之間的類型必須相同。
e.g.:

[myDrop.hs]

-- file: ch02/myDrop.hs

myDrop :: Int -> [a] -> [a]
myDrop n xs = if n <= 0 || null xs    -- ## null用法
              then xs   -- 縮進不可省略
              else myDrop (n - 1) (tail xs) -- 縮進不可省略

-- 代換(substitution)和重寫(rewriting)
-- 代換了變量n和xs
-- 重寫了myDrop函數

-- ## 惰性求值
-- 也可寫成一行 e.g.[myDropX.hs](ch02/myDrop.hs)

-- ## 條件求值
-- null xs not equals to xs == null
-- then 和 else 之後的表達式稱為“分支”,
-- 不同分支之間的類型必須相同。
-- 而if不是分支。


-- e.g.
-- Prelude> if True then 1 else "foo"

-- <interactive>:2:14:
--     No instance for (Num [Char])
--         arising from the literal `1'
--     Possible fix: add an instance declaration for (Num [Char])
--     In the expression: 1
--     In the expression: if True then 1 else "foo"
--     In an equation for `it': it = if True then 1 else "foo"

->
可精簡到一行 [myDropX.hs]

-- file: ch02/myDropX.hs
myDropX n xs = if n <= 0 || null xs then xs else myDropX (n - 1) (tail xs)

惰性求值#

e.g. [isOdd.hs]

-- file: ch02/isOdd.hs
isOdd n = mod n 2 == 1

-- ghci> isOdd (1+2)
-- True

--in general:XXXXXX
-- first: (1+2)
-- second: mod 3 2
-- third: 1 == 1
-- True

--but in haskell:
--(1+2) 最後算!當真正有需要的時候再計算出 isOdd (1 + 2) 的值
--追蹤未求值表達式的記錄被稱為塊(chunk)

遞歸#

注意惰性求值,遞歸 -> 終止遞歸 -> 遞歸返回
解釋
e.g. [myDrop.hs]

多態#

參數多態#

Prelude> :type last
last :: [a] -> a
ghci> last [1,2,3]
3

如果將一個類型為 [Char] 的列表傳給 last ,那麼編譯器就會用 Char 代換 last 函數類型簽名中的所有 a ,從而得出一個類型為 [Char] -> Char 的 last 函數。諸如此類可以是 Int,可以是任何類型。這種類型的多態被稱為參數多態。

參數多態沒有辦法知道輸入參數的實際類型

缺少#

Haskell 沒有子類多態和強制多態(coercion polymorphism)。

多參數函數的類型#

e.g.

Prelude> :type take
take :: Int -> [a] -> [a]
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。