Monoid 是一個類型類。 字典對 Monoid 的解釋是:app
獨異點,帶有中性元的半羣;函數
這應該是範疇論裏的東西,反正我目前是看不懂這個什麼羣。學習
咱們先學習 newtypethis
data 關鍵字能夠建立類型; type 關鍵字能夠給如今類型設置別名; instance 關鍵字可讓類型變成類型類的實例;spa
newtype 關鍵字是根據現有數據類型建立新類型。 newtype 跟 data 很像,可是速度更快,不過功能更少,只能接受值構造器,值構造器只能有一個參數。code
newtype CharList = CharList { getCharList :: [Char] } deriving (Eq, Show)
ghci> CharList "this will be shown!"
CharList {getCharList = "this will be shown!"}
ghci> CharList "benny" == CharList "benny"
True
ghci> CharList "benny" == CharList "oisters"
False
複製代碼
咱們先用 *
和 ++
做比喻ci
1 * 某值
的結果都是某值[] ++ 某列表
的結果都是某列表(3 * 4) * 5
和 3 * (4 * 5)
同樣([1,2] ++ [3,4]) ++ [5,6]
和 [1,2] ++ ([3,4] ++ [5,6])
同樣再看 Monoid開發
一個 Monoid 的實例由一個知足結合律的二元函數和一個單位元組成。get
在 * 的定義中 1 是單位元,在++ 的定義中[] 是單位元。string
class Monoid m where
mempty :: m
mappend :: m -> m -> m
mconcat :: [m] -> m
mconcat = foldr mappend mempty
複製代碼
因此大部分實例只須要定義 mempty 和 mappend 就好了。默認 concat 大部分時候都夠用了。
mempty `mappend` x = x
x `mappend` mempty = x
(x `mappend` y) `mappend` z = x `mappend` (y `mappend` z)
-- 並不要求 a `mappend` b = b `mappend` a,這是交換律
複製代碼
Haskell 不會強制要求這些定律成立,因此開發者要本身保證。
Data.Monoid 導出了 Product,定義以下
newtype Product a=Product{getProduct::a}
deriving(Eq,Ord,Read,Show,Bounded)
複製代碼
他的 Monoid 實例定義以下:
instance Num a=> Monoid ( Product a) where
mempty=Product 1
Product x `mappend` Product y= Product (x * y)
複製代碼
使用方法:
ghci> getProduct $ Product 3 `mappend` Product 9
27
ghci> getProduct $ Product 3 `mappend` mempty
3
ghci> getProduct $ Product 3 `mappend` Product 4 `mappend` Product 2
24
ghci> getProduct.mconcat.map Product $ [3,4,2]
24
複製代碼
Product 使得 Num 以乘法的形式知足 Monoid 的要求。
Sum 則是用加法:
ghci> getSum $ Sum 2 `mappend` Sum 9
11
ghci> getSum $ mempty `mappend` Sum 3
3
ghci> getSum.mconcat.mapSum $ [1,2,3]
6
複製代碼
書中還說了不少其餘相似的例子。
不過我更關注的是 monad,因此接直接跳過了。