Haskell學習心得

Haskell學習心得

話說程序員要每年學一門編程語言.2020年,目標Haskell.

特性

  • 柯里化
    Haskell的函數,只有單參數函數.它的多參數函數,其實只是返回了另一個函數.
    所以在進行部分參數應用的時候,會非常的自然.
  • 運算符
    所有的運算符也是函數,和函數不同的是,運算符的結合性和優先級可以自定義.函數的結合性和優先級是固定的.
  • 強類型和類型推導
    定義函數時,可以聲明類型,也可以不聲明類型.如果不聲明類型,Haskell會根據上下文推導出來類型.它的自動推導功能十分強大.
  • 函數調用不需要括號,參數之間用空格分隔
    和其他語言用括號和逗號的風格不同,Haskell裏面調用函數通過空格分隔函數名和參數,也通過空格分隔多個參數.配合柯里化,函數應用符$,可以實現另人驚豔的效果,比如其他語言中f(g(h(x)))這樣的調用,可以寫成f $ g $ h x,將代碼的嵌套風格變成了扁平的風格.
  • 支持模式匹配
    十分方便解構數據,判斷類型,代碼寫起來也非常優雅.
  • 支持lambda表達式
  • 不可變變量
    變量一旦定義不可重新賦值.
  • 前綴運算符,中綴運算符,後綴運算符,混合位置運算符
    前綴運算符用中綴形式調用.中綴運算符可以使用前綴形式調用.
    if then else是一個混合位置運算符
  • 惰性求值
    在真正需要的時候才進行計算,很容易定義無限列表.
  • 隔離純函數和非純函數
    Haskell中嚴格區分純與不純函數.一旦一個函數變成不純函數,那麼它的調用者也是不純函數.從純函數取結果和從不純函數取結果的方式不一樣.
  • 函數調用符$
    這個可以實現f(g(x))寫成f $ g x這樣的效果.
  • 管道運算符|>
    可以實現參數寫在前面,函數寫在後面的效果.
    比如text |> lines |> map (++"!!!")的語義爲,將文本text按換行符分隔,得到一個列表,然後列表中每個字符串後面拼接3個感嘆號.
  • 類型,類型類,kind
    如果拿java作比喻的話,Haskell中的類型(type)類似於java的class
    Haskell中的類型類(typeclass)類似於java的interface(可以定義默認實現的那種)
    Haskell中的kind,就是類型的類別(好吧,不理解沒關係,就是個概念而已).
  • 類型構造器和數據構造器
    Haskell中區分類型構造器和數據構造器.
    在java中構造器必須和類型名稱相同.Haskell中一個類型可以有多個數據構造器.
  • 代碼結構
    Haskell由多個模塊組成.一個模塊由模塊導入,模塊和導出聲明,類型定義,函數定義,運算符定義,變量定義組成.函數由函數聲明和函數體組成.函數體由表達式組成.Haskell中沒有語句.最後一個表達式的值就是函數的返回值.
  • 列表生成器
    類似於python中的列表生成器,python應該是借鑑Haskell這類語言的.
  • 容器與盒子
    雖然沒有明確的定義,但是一般我們把參數化類型當成容器.把參數化類型構造出的類型的值當做盒子.
  • Functor,Applicative,Monad
    這些類型類,定義了相關的處理盒子的函數.因爲非純函數操作,異常處理操作等,Haskell會將它們的值裝進盒子,定義一系列操作盒子的函數,可以方便調用非純函數.

心得

  • 思維方式的改變.命令式編程,我們告訴程序問題如何解決.函數式編程我們告訴程序問題是什麼.
  • 函數參數都是基於位置的,不支持命名參數和默認參數.這對代碼的可讀性是一個非常大的挑戰.從一個函數的聲明中,我們只能看到類型信息.
    一門語言的函數調用形式如何設計,其實是需要很講究的.柯里化形式有它的優勢(簡潔,可扁平化,可實現管道風格-相當於oop裏面的鏈式調用吧,易實現DSL),也有它的劣勢(需要記住各位置填什麼參數.想想用shell命令時經常弄錯參數位置的情形吧).從工程角度看,基於位置的方式可讀性會差很多.
  • Haskell中各種運算符,比如>>=,>>>,>>,<=<,=<<,<$>,<*>,*>,|>,<|>,<*,,它們的語義太豐富,晦澀難懂.讀源代碼的時候,大腦需要處理太多信息.如果再加點料,配上一些高階函數,那"酸爽",誰用誰知道.
    如果程序的簡潔性需要以可讀性爲代價,那麼我寧願不那麼簡潔.
  • 副作用的處理.Haskell中強制隔離pure操作和IO操作.這個思想非常好,用於java中也獲益匪淺.可以大大提高代碼的易測試性,降低耦合性.
  • 異常處理.有一種異常處理思想深得我心,let it crash.這種思想認爲,程序出異常了,大部分情況下我們並不需要在方法裏面捕獲它,我們只需要不管它,讓它一直往上拋即可.Haskell喜歡用Maybe,Either來表示異常.我對這種不能打印異常棧的處理方式深表懷疑.
  • 命名空間.在java中,不推薦import *.當然,haskell裏面也可以import SomeModule (f1,f2)這樣解決.但是,不同模塊的函數名衝突了,就需要起別名了.
  • 多行字符串.貌似沒有看到關於Haskell中處理多行字符串的方案.
  • 惰性求值與棧溢出.容易寫出看上去沒啥問題,實際上會棧溢出的代碼.
  • Haskell中有專門用於寫編譯器的庫.嗯…這個用來創造自己的編程語言,真的太棒了.
  • 有些經典算法的描述,是通過命令式方式描述的.要用haskell實現,可能要費一些腦細胞.
  • 暫時想到這麼多了,打算複習並整理一遍數據結構和算法.用haskell實現,體驗一下.如果感覺還不錯,後面我就是haskell粉了.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章