簡體   English   中英

Haskell中的“雙重”功能組合

[英]“Double” function composition in Haskell

我從編譯器的建議中發現了一些對我來說很奇怪的東西。

我做了一個數據類型來表示二進制數字,如下所示:

data Bin = Zero | One

我選擇將多位二進制數表示為Bin類型的列表,如下所示:

myNum :: [Bin]
myNum = [One, Zero, One, One] -- represents the number 1011

自然地,我想以一種更方便的方式顯示我的二進制數,所以我創建了一個Show實例來為我做這件事:

instance Show Bin where
    show Zero = "0"
    show One  = "1"
    showList []     = showString ""
    showList (x:xs) = showString (show x) . showList xs

print myNum ,並且print myNum正確顯示1011

我在Haskell還是很新,這是我第一次使用showList。 但這對我來說很有意義。 由於showList的類型為[a] -> ShowS (它本身是[a] -> (String -> String)的別名),因此我了解到我是通過使用函數組合來“串聯”列表的元素的。 但是編譯器建議我使用showList函數並重新定義它:

Warning: Use foldr
  Found:
    showList [] = showString ""
    showList (x : xs) = showString (show x) . showList xs
  Why not:
    showList xs = foldr ((.) . showString . show) (showString "") xs

而且,一旦我替換了它的建議,它便提出了進一步的建議:

Error: Eta reduce
  Found:
    showList xs = foldr ((.) . showString . show) (showString "") xs
  Why not:
    showList = foldr ((.) . showString . show) (showString "")

我了解Eta減少錯誤,因為通常最好編寫無點函數。 但是我在第一次轉換時遇到了麻煩。 我看到foldr的第二個參數是“基本情況”正確的身份,但是我很難理解foldr的第一個參數中發生了什么。 所以我有兩個問題:

  1. 如何重寫((.) . showString . show) 例如,我知道(f . g) x可以重寫為f (gx)
  2. 這實際上在文件foldr的上下文中有什么作用?

如何重寫它,如下所示,首先讓我們將合成模式分解為一個單獨的函數

 compose :: [a -> a] -> a -> a
 compose = foldr (.) id

您可以將其可視化為獲取列表f : g : h : []並將[]替換為id: . 給你留下f . g . h . id f . g . h . id f . g . h . idf . g . h f . g . h f . g . h

接下來,讓我們用它來重寫您的示例,使其更清晰易讀

  instance Show Bin where
    showList = compose . map (showString . show)

現在,盡管功能相同,但它比您現在的要清晰一些。 實際上,由於GHC可能將其融合(?),因此甚至可能以相同的方式編譯。 我們將每個項目轉換為ShowS String -> StringShowS ,然后將它們全部組成。 提供名稱和類型來compose ,可以更輕松地了解正在發生的事情。

我想這也可以寫成

 showList = appEndo . mconcat . map (Endo . showString . show)

這與上面的相同,但是依賴於以下事實: mconcat a -> a形成一個monoid,而mconcat推廣了將一個monoid列表組合為一個的想法。 我們需要Endo位,因為實際上為

newtype Endo a = End {appEndo :: a -> a}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM