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