12

I am using Data.Sequence instead lists for better performance. With lists we can do the following

foo :: [Int] -> Int
foo [] m = m
foo (x:xs) m = ...

How can this be accomplished with Data.Sequence. I have tried the following:

foo:: S.Seq Int -> Int
foo S.empty m = m
foo (x S.<: xs) m = ...

I think the solution involves using S.viewl and S.viewr, but cannot seem to figure out how.

Cactus
  • 27,075
  • 9
  • 69
  • 149
abden003
  • 1,325
  • 7
  • 24
  • 48

2 Answers2

16

As of GHC 7.8, you can use pattern synonyms together with view patterns for this purpose:

{-# LANGUAGE ViewPatterns, PatternSynonyms #-}

import qualified Data.Sequence as Seq

pattern Empty   <- (Seq.viewl -> Seq.EmptyL)
pattern x :< xs <- (Seq.viewl -> x Seq.:< xs)
pattern xs :> x <- (Seq.viewr -> xs Seq.:> x)

As of GHC 7.10, you can also make it into a bidirectional pattern synonym, so that Empty, (:<) and (:>) can be used as "constructors" as well:

{-# LANGUAGE ViewPatterns, PatternSynonyms #-}

import qualified Data.Sequence as Seq

pattern Empty   <- (Seq.viewl -> Seq.EmptyL)  where Empty = Seq.empty
pattern x :< xs <- (Seq.viewl -> x Seq.:< xs) where (:<)  = (Seq.<|) 
pattern xs :> x <- (Seq.viewr -> xs Seq.:> x) where (:>)  = (Seq.|>) 
Cactus
  • 27,075
  • 9
  • 69
  • 149
  • 1
    Excellent, I had no idea this made it into 7.10. Why is the [GHC ticket](https://ghc.haskell.org/trac/ghc/ticket/8581) still open for it though? – András Kovács Jun 29 '15 at 06:13
  • @AndrásKovács: erhmm... I've left it open because the matcher vs builder type context issues in that ticket haven't been completely addressed yet. – Cactus Jun 29 '15 at 06:30
  • Note, [per the wiki](https://gitlab.haskell.org/ghc/ghc/-/wikis/pattern-synonyms/complete-sigs), that "[t]he exhaustiveness checker currently chokes on pattern synonyms." We can reassure the compiler that our patterns are exhaustive using the [COMPLETE pragma](https://gitlab.haskell.org/ghc/ghc/-/wikis/pattern-synonyms/complete-sigs#syntax). See also [this answer](https://stackoverflow.com/a/74526666/12162258). – thisisrandy Nov 22 '22 at 01:59
14

ViewPatterns is probably the way to go here. Your code doesn't work because you need to call viewl or viewr on your Seq first to get something of type ViewL or ViewR. ViewPatterns can handle that pretty nicely:

{-# LANGUAGE ViewPatterns #-}

foo (S.viewl -> S.EmptyL)    = ... -- empty on left
foo (S.viewl -> (x S.:< xs)) = ... -- not empty on left

Which is equivalent to something like:

foo seq = case S.viewl seq of
    S.EmptyL    -> ...
    (x S.:< xs) -> ...
Cactus
  • 27,075
  • 9
  • 69
  • 149
jhickner
  • 1,043
  • 10
  • 15