Skip to content

Instantly share code, notes, and snippets.

@dz1984
Last active May 28, 2018 08:01
Show Gist options
  • Save dz1984/0d0313ed75f1113d9846 to your computer and use it in GitHub Desktop.
Save dz1984/0d0313ed75f1113d9846 to your computer and use it in GitHub Desktop.
抄錄學習 Haskell 筆記。
  • 使用處理 List 的函數來對字串進行操作。 將兩個 List 合併是很常見的操作,這可以通過 ++ 運算子實現。

  • 用 : 運算子往一個 List 前端插入元素會是更好的選擇。

  • : 運算子可以連接一個元素到一個 List 或者字串之中,而 ++ 運算子則是連接兩個 List。若要使用 ++ 運算子連接單個元素到一個 List 之中,就用方括號把它括起使之成為單個元素的 List。

  • 可以使用 !! 運算子,取得 List 中的元素(索引的下標為 0)。

  • head 返回一個 List 的頭部,也就是 List 的首個元素。

  • tail 返回一個 List 的尾部,也就是 List 除去頭部之後的部分。

  • last 返回一個 List 的最後一個元素。

  • init 返回一個 List 除去最後一個元素的部分。

  • length 返回一個 List 的長度。

  • null 檢查一個 List 是否為空。如果是,則返回 True,否則返回 False。

  • reverse 將一個 List 反轉。

  • take 返回一個 List 的前幾個元素。

  • drop 與 take 的用法大體相同,它會刪除一個 List 中的前幾個元素。

  • maximum 返回一個 List 中最大的那個元素。minimun 返回最小的。

  • sum 返回一個 List 中所有元素的和。

  • product 返回一個 List 中所有元素的積。

  • elem 判斷一個元素是否在包含于一個 List,通常以中綴函數的形式呼叫它。

  • fst 返回一個序對的首項。 snd 返回序對的尾項。(Note:這兩個函數僅對序對有效,而不能應用於三元組,四元組和五元組之上。稍後,我們將過一遍從 Tuple 中取數據的所有方式。)

  • zip 用來生成一組序對 (Pair) 的 List。它取兩個 List,然後將它們交叉配對,形成一組序對的 List。

  • => 符號。它左邊的部分叫做型別約束。我們可以這樣閲讀這段型別聲明:"相等函數取兩個相同型別的值作為參數並回傳一個布林值,而這兩個參數的型別同在 Eq 類之中(即型別約束)"

  • Eq 這一 Typeclass 提供了判斷相等性的介面,凡是可比較相等性的型別必屬於 Eq class。

  • Ord 包含可比較大小的型別。

  • Show 的成員為可用字串表示的型別。

  • Read 是與 Show 相反的 Typeclass。read 函數可以將一個字串轉為 Read 的某成員型別。

  • 模式的順序是如此重要:它總是優先匹配最符合的那個,最後才是那個萬能的。

  • 在定義模式時,一定要留一個萬能匹配的模式,這樣我們的程序就不會為了不可預料的輸入而崩潰了。

  • as 模式,就是將一個名字和 @ 置於模式前,可以在按模式分割什麼東西時仍保留對其整體的引用。使用 as 模式通常就是為了在較大的模式中保留對整體的引用,從而減少重複性的工作。

  • 不可以在模式匹配中使用 ++

  • 模式用來檢查一個值是否合適並從中取值,而 guard 則用來檢查一個值的某項屬性是否為真。

  • 處理多個條件分支時 guard 的可讀性要高些,並且與模式匹配契合的很好。

  • 最後的那個 guard 往往都是 otherwise,它的定義就是簡單一個 otherwise = True ,捕獲一切。

  • guard 可以在含有任意數量參數的函數中使用。

  • 函數在 where 綁定中定義的名字只對本函數可見,因此我們不必擔心它會污染其他函數的命名空間。where 綁定不會在多個模式中共享。如果你在一個函數的多個模式中重複用到同一名字,就應該把它置於全局定義之中。where 綁定也可以使用模式匹配!

  • 定義一個函數的時候也寫幾個輔助函數擺在 where 綁定中。而每個輔助函數也可以透過 where 擁有各自的輔助函數。

  • let 綁定與 where 綁定很相似。where 綁定是在函數底部定義名字,對包括所有 guard 在內的整個函數可見。let 綁定則是個表達式,允許你在任何位置定義局部變數,而對不同的 guard 不可見。正如 Haskell 中所有賦值結構一樣,let 綁定也可以使用模式匹配。

  • let 的格式為 let [bindings] in [expressions]。在 let 中綁定的名字僅對 in 部分可見。let 裡面定義的名字也得對齊到一列。不難看出,這用 where 綁定也可以做到。

  • let 綁定本身是個表達式,而 where 綁定則是個語法結構。

  • 可以把 let 綁定放到 List Comprehension 中 。

  • let 是個表達式,定義域限制的相當小,因此不能在多個 guard 中使用。

  • 看得出,case表達式的語法十分簡單:

    case expression of pattern -> result   
                       pattern -> result   
                       pattern -> result   
                       ...  
  • 遞迴其中的固定模式:先定義一個邊界條件,再定義個函數,讓它從一堆元素中取一個並做點事情後,把餘下的元素重新交給這個函數。

  • 使用遞迴來解決問題時應當先考慮遞迴會在什麼樣的條件下不可用, 然後再找出它的邊界條件和單位元, 考慮參數應該在何時切開(如對 List 使用模式匹配), 以及在何處執行遞迴。

  • 為何只用箭頭來分隔參數和回傳值型別。可以使用 max 函式為例子。你可以這樣想,

    max :: (Ord a) => a -> a -> a
    
    -- same as
    
    max :: (Ord a) => a -> (a->a)
  • 中綴函數也可以不全呼叫,用括號把它和一邊的參數括在一起就行了。這回傳一個取一參數並將其補到缺少的那一端的函數。

  • takeWhile 函數,它取一個限制條件和 List 作參數,然後從頭開始遍歷這一 List,並回傳符合限制條件的元素。

  • lambda 就是匿名函數。有些時候我們需要傳給高階函數一個函數,而這函數我們只會用這一次,這就弄個特定功能的 lambda。編寫 lambda,就寫個 \ (因為它看起來像是希臘字母的 lambda -- 如果你斜視的厲害),後面是用空格分隔的參數,-> 後面就是函數體。通常我們都是用括號將其括起,要不然它就會佔據整個右邊部分。

  • fold 取一個二元函數,一個初始值(我喜歡管它叫累加值)和一個需要摺疊的 List。這個二元函數有兩個參數,即累加值和 List 的首項(或尾項),回傳值是新的累加值。然後,以新的累加值和新的 List 首項呼叫該函數,如是繼續。到 List 遍歷完畢時,只剩下一個累加值,也就是最終的結果。

  • foldl 函數,也叫做左摺疊。它從 List 的左端開始摺疊,用初始值和 List 的頭部呼叫這二元函數,得一新的累加值,並用新的累加值與 List 的下一個元素呼叫二元函數。如是繼續。

  • 右摺疊 foldr 的行為與左摺疊相似,只是累加值是從 List 的右邊開始。同樣,左摺疊的二元函數取累加值作首個參數,當前值為第二個參數(即 \acc x -> ...),而右摺疊的二元函數參數的順序正好相反(即 \x acc -> ...)。這倒也正常,畢竟是從右端開始摺疊。

  • 所有遍歷 List 中元素並據此回傳一個值的操作都可以交給 fold 實現。

  • foldl1foldr1 的行為與 foldl 和 foldr 相似,只是你無需明確提供初始值。他們假定 List 的首個(或末尾)元素作為起始值,並從旁邊的元素開始摺疊。

  • scanlscanrfoldlfoldr 相似,只是它們會記錄下累加值的所有狀態到一個 List。也有 scanl1scanr1

  • $ 函數。它也叫作函數呼叫符。

  • 普通的函數呼叫符有最高的優先順序,而 $ 的優先順序則最低。用空格的函數呼叫符是左結合的。$ 則是右結合的。

  • 函數組合的用處之一就是生成新函數,並傳遞給其它函數。

  • intersperse 取一個元素與 List 作參數,並將該元素置於 List 中每對元素的中間。

  • intercalate 取兩個 List 作參數。它會將第一個 List 交叉插入第二個 List 中間,並返回一個 List.

  • transpose 函數可以反轉一組 List 的 List。

  • concat 把一組 List 連接為一個 List。

  • concatMap 函數與 map 一個 List 之後再 concat 它等價.

  • and 取一組布林值 List 作參數。只有其中的值全為 True 的情況下才會返回 True。

  • or 與 and 相似,一組布林值 List 中若存在一個 True 它就返回 True.

  • anyall 取一個限制條件和一組布林值 List 作參數,檢查是否該 List 的某個元素或每個元素都符合該條件。通常較 map 一個 List 到 and 或 or 而言,使用 any 或 all 會更多些。

  • iterate 取一個函數和一個值作參數。它會用該值去呼叫該函數並用所得的結果再次呼叫該函數,產生一個無限的 List.

  • splitAt 取一個 List 和數值作參數,將該 List 在特定的位置斷開。返回一個包含兩個 List 的二元組.

  • takeWhile 這一函數十分的實用。它從一個 List 中取元素,一旦遇到不符合條件的某元素就停止.

  • dropWhile 與此相似,不過它是扔掉符合條件的元素。一旦限制條件返回 False,它就返回 List 的餘下部分。

  • spantakeWhile 有點像,只是它返回兩個 List。第一個 List 與同參數呼叫 takeWhile 所得的結果相同,第二個 List 就是原 List 中餘下的部分。

  • span 是在條件首次為 False 時斷開 List,而 break 則是在條件首次為 True 時斷開 List。break p 與 span (not . p) 是等價的. break 返回的第二個 List 就會以第一個符合條件的元素開頭。

  • sort 可以排序一個 List,因為只有能夠作比較的元素才可以被排序,所以這一 List 的元素必須是 Ord 型別類的實例型別。

  • group 取一個 List 作參數,並將其中相鄰並相等的元素各自歸類,組成一個個子 List.

  • initstailsinittail 相似,只是它們會遞歸地呼叫自身直到什麼都不剩

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment