[英]What's the best style in Haskell
感謝Erik Meijer的演講,也取得了重大進展。 好手表,也許暗示。 Haskell允許使用幾種方法來編寫相同的函數。 就效率和可讀性而言,哪一個最好?
sqr' = \x -> x * x
sqr'' x = x * x
sqr''' = (^2)
在這兩個頂級定義之間:
sqr' = \x -> x * x
sqr'' x = x * x
第二個在Haskell程序中幾乎是普遍首選的。 搜索幾乎所有現實世界中的Haskell代碼塊,您會發現第二個示例很多,但第一個示例很少。 相反,“ lambda抽象”(即\\x -> ...
語法)最常用於定義匿名函數,以將其作為參數傳遞給高階函數。
選擇第二種語法有兩個原因。 首先,從字面上看,它更加簡潔,從可讀性的角度來看,它包含更少的不同語法元素(即並置和=
運算符,而不是並置=
, \\
和->
)。 它還很好地概括了使用多個模式定義函數的常見Haskell習慣用法:
factorial 0 = 1
factorial n | n > 0 = n * factorial (n-1)
要使用lambda語法執行此操作,您需要添加一個顯式的case
構造,其中涉及另一套語法元素。
之間:
sqr'' x = x * x
sqr''' = (^2)
或者-也許是更公平的比較:
sqr'''' x = x^2
sqr''' = (^2)
這更多是個人喜好問題。 許多Haskell程序員喜歡所謂的無點語法的外觀,其中較大的函數是使用高階函數和/或沒有明確參數的組合函數鏈組成的,例如:
mostFrequentWord
= head . maximumBy (comparing length) . group . sort . words
和sqr'''
類的定義更符合這種總體風格。
就這些形式之間的含義差異而言,實際上有點復雜。 如果您采用以下模塊,則出於晦澀的原因,它們與稱為“單態性限制”和“默認規則”的事情有關:
module Square where
sqr' = \x -> x * x
sqr'' x = x * x
sqr''' = (^2)
並用ghc -O
編譯, sqr'
和sqr'''
的定義是等效的-兩者都將專門用於Integer
類型,並且將生成完全相同的代碼。 (使用GHC 8.0.2測試)。 相反, sqr''
保持多態性並帶有簽名Num a => a -> a
sqr''
Num a => a -> a
,這意味着它可以對任何數字類型進行操作。
如果添加頂級類型簽名(無論如何,都是好的做法!),如下所示:
module Square where
sqr', sqr'', sqr''' :: (Num a) => a -> a
sqr' = \x -> x * x
sqr'' x = x * x
sqr''' = (^2)
然后它們都生成完全相同的代碼。 您可以使用以下方法查看生成的“核心”(編譯器在編譯過程中創建的中間點,類似於Haskell的中間語言),從而自己驗證這一點:
ghc -O -ddump-simpl -dsuppress-all -fforce-recomp Square.hs
在生成的核心中,您將看到定義:
sqr' = \ @ a_aBC $dNum_aLW x_arx -> * $dNum_aLW x_arx x_arx
看起來很奇怪,但從根本上說,將適當的Num
類型的*
操作應用於參數x_arx x_arx
。 為兩個變體生成的代碼:
sqr'' = sqr'
sqr''' = sqr'
表明GHC認為它們和sqr'
之間沒有區別,因此在語義或性能上也沒有區別。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.