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.
Just to address the error message you received and what it means:
So the compiler expected your function to be of type:
BS.ByteString -> BS.ByteString
because you gave it that type in your signature. Yet it inferred (by looking at the body of your function) that the function is actually of type[a] -> [a]
. There is a mismatch there so the compiler complains.The trouble is you are thinking of (:) and [] as syntactic sugar, when they are actually just the constructors for the list type (which is VERY different from ByteString).
For this, I would pattern match on the result of
uncons :: ByteString -> Maybe (Word8, ByteString)
.Pattern matching in Haskell only works on constructors declared with 'data' or 'newtype.' The ByteString type doesn't export its constructors you cannot pattern match.
Patterns use data constructors. http://book.realworldhaskell.org/read/defining-types-streamlining-functions.html
Your
empty
is just a binding for the first parameter, it could have beenx
and it would not change anything.You can't reference a normal function in your pattern so
(x cons empty)
is not legal. Note: I guess(cons x empty)
is really what you meant but this is also illegal.ByteString
is quite different fromString
.String
is an alias of[Char]
, so it's a real list and the:
operator can be used in patterns.ByteString is
Data.ByteString.Internal.PS !(GHC.ForeignPtr.ForeignPtr GHC.Word.Word8) !Int !Int
(i.e. a pointer to a native char* + offset + length). Since the data constructor of ByteString is hidden, you must use functions to access the data, not patterns.Here a solution (surely not the best one) to your UTF-16 filter problem using the
text
package:You can use view patterns for such things
The latest version of GHC (7.8) has a feature called pattern synonyms which can be added to gawi's example:
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:
in which case
dropR
can work on both[Word8]
andByteString
:And for the hell of it:
You can see more on my post on pattern synonyms.