Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell Bytestrings: How to pattern match?

I'm a Haskell newbie, and having a bit of trouble figuring out how to pattern match a ByteString. The [Char] version of my function looks like:

dropAB :: String -> String dropAB []       = [] dropAB (x:[])   = x:[] dropAB (x:y:xs) = if x=='a' && y=='b'                   then dropAB xs                   else x:(dropAB $ y:xs)  

As expected, this filters out all occurrences of "ab" from a string. However, I have problems trying to apply this to a ByteString.

The naive version

dropR :: BS.ByteString -> BS.ByteString dropR []         = [] dropR (x:[])     = [x] <...> 

yields

Couldn't match expected type `BS.ByteString'        against inferred type `[a]' In the pattern: [] In the definition of `dropR': dropR [] = [] 

[] is clearly the culprit, as it is for a regular String not a ByteString. Subbing in BS.empty seems like the right thing but gives "Qualified name in the binding position: BS.empty." Leaving us to try

dropR :: BS.ByteString -> BS.ByteString dropR empty              = empty         dropR (x cons empty)     = x cons empty <...> 

this gives "parse error in pattern" for (x cons empty). I don't really know what else I can do here.

As a side note, what I'm trying to do with this function is to filter out a specific UTF16 character from some text. If there's a clean way to accomplish that, I'd love to hear it, but this pattern matching error seems like something that a newbie haskeller should really understand.

like image 612
LOS Avatar asked Oct 29 '10 22:10

LOS


People also ask

How is pattern matching done in Haskell?

Overview. We use pattern matching in Haskell to simplify our codes by identifying specific types of expression. We can also use if-else as an alternative to pattern matching. Pattern matching can also be seen as a kind of dynamic polymorphism where, based on the parameter list, different methods can be executed.

What is pattern matching in Haskell explain with example?

In a functional language, pattern matching involves checking an argument against different forms. A simple example involves recursively defined operations on lists. I will use OCaml to explain pattern matching since it's my functional language of choice, but the concepts are the same in F# and Haskell, AFAIK.


2 Answers

You can use view patterns for such things

{-# LANGUAGE ViewPatterns #-}     import Data.ByteString (ByteString, cons, uncons, singleton, empty) import Data.ByteString.Internal (c2w)   dropR :: ByteString -> ByteString dropR (uncons -> Nothing) = empty dropR (uncons -> Just (x,uncons -> Nothing)) = singleton x dropR (uncons -> Just (x,uncons -> Just(y,xs))) =     if x == c2w 'a' && y == c2w 'b'     then dropR xs     else cons x (dropR $ cons y xs) 
like image 72
Ed'ka Avatar answered Sep 20 '22 15:09

Ed'ka


The latest version of GHC (7.8) has a feature called pattern synonyms which can be added to gawi's example:

{-# LANGUAGE ViewPatterns, PatternSynonyms #-}  import Data.ByteString (ByteString, cons, uncons, singleton, empty) import Data.ByteString.Internal (c2w)  infixr 5 :<  pattern b :< bs <- (uncons -> Just (b, bs)) pattern Empty   <- (uncons -> Nothing)  dropR :: ByteString -> ByteString dropR Empty          = empty dropR (x :< Empty)   = singleton x dropR (x :< y :< xs)   | x == c2w 'a' && y == c2w 'b' = dropR xs   | otherwise                    = cons x (dropR (cons y xs)) 

Going further you can abstract this to work on any type class (this will look nicer when/if we get associated pattern synonyms). The pattern definitions stay the same:

{-# LANGUAGE ViewPatterns, PatternSynonyms, TypeFamilies #-}  import qualified Data.ByteString as BS import Data.ByteString (ByteString, singleton) import Data.ByteString.Internal (c2w) import Data.Word  class ListLike l where   type Elem l    empty  :: l   uncons :: l -> Maybe (Elem l, l)   cons   :: Elem l -> l -> l  instance ListLike ByteString where   type Elem ByteString = Word8    empty  = BS.empty   uncons = BS.uncons   cons   = BS.cons  instance ListLike [a] where   type Elem [a] = a    empty         = []   uncons []     = Nothing   uncons (x:xs) = Just (x, xs)   cons          = (:) 

in which case dropR can work on both [Word8] and ByteString:

-- dropR :: [Word8]    -> [Word8] -- dropR :: ByteString -> ByteString dropR :: (ListLike l, Elem l ~ Word8) => l -> l dropR Empty          = empty dropR (x :< Empty)   = cons x empty dropR (x :< y :< xs)   | x == c2w 'a' && y == c2w 'b' = dropR xs   | otherwise                    = cons x (dropR (cons y xs)) 

And for the hell of it:

import Data.ByteString.Internal (w2c)  infixr 5 :•     pattern b :• bs <- (w2c -> b) :< bs  dropR :: (ListLike l, Elem l ~ Word8) => l -> l dropR Empty              = empty dropR (x   :< Empty)     = cons x empty dropR ('a' :• 'b' :• xs) = dropR xs dropR (x   :< y   :< xs) = cons x (dropR (cons y xs)) 

You can see more on my post on pattern synonyms.

like image 44
Iceland_jack Avatar answered Sep 22 '22 15:09

Iceland_jack