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