PatternSynonyms

模式同義詞模式的抽象,類似於函式是表示式抽象的方式。

在這個例子中,讓我們看一下 Data.Sequence 暴露的介面,讓我們看看如何使用模式同義詞來改進它。所述 Seq 型別是,在內部,使用一個資料型別複雜表示實現良好的漸近複雜用於各種操作,最值得注意的是兩個 O(1)(未)consing 和(UN)snocing。

但是這種表示是笨拙的,並且它的一些不變數不能在 Haskell 的型別系統中表達。因此,Seq 型別作為抽象型別暴露給使用者,以及保持不變的訪問器和建構函式,其中包括:

empty::Seq a

(<|) :: a -> Seq a -> Seq a
data ViewL a = EmptyL | a :< (Seq a)
viewl::Seq a -> ViewL a

(|>) :: Seq a -> a -> Seq a 
data ViewR a = EmptyR | (Seq a) :> a 
viewr::Seq a -> ViewR a

但是使用這個介面可能有點麻煩:

uncons::Seq a -> Maybe (a, Seq a)
uncons xs = case viewl xs of
    x :< xs' -> Just (x, xs')
    EmptyL -> Nothing

我們可以使用檢視模式進行一些清理:

{-# LANGUAGE ViewPatterns #-}

uncons::Seq a -> Maybe (a, Seq a)
uncons (viewl -> x :< xs) = Just (x, xs)
uncons _ = Nothing

使用 PatternSynonyms 語言擴充套件,我們可以通過允許模式匹配假裝我們有一個 consoc 或 snoc-list 來提供更好的介面:

{-# LANGUAGE PatternSynonyms #-}
import Data.Sequence (Seq)
import qualified Data.Sequence as Seq

pattern Empty::Seq a
pattern Empty <- (Seq.viewl -> Seq.EmptyL)

pattern (:<) :: a -> Seq a -> Seq a
pattern x :< xs <- (Seq.viewl -> x Seq.:< xs)

pattern (:>) :: Seq a -> a -> Seq a
pattern xs :> x <- (Seq.viewr -> xs Seq.:> x)

這使我們能夠以非常自然的方式編寫 uncons

uncons::Seq a -> Maybe (a, Seq a)
uncons (x :< xs) = Just (x, xs)
uncons _ = Nothing