2010-10-29 77 views
25

我是一个Haskell新手,并且在找出如何匹配ByteString的模式时遇到了一些麻烦。该[Char]版本我的功能看起来像:Haskell Bytestrings:如何模式匹配?

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

正如预期的那样,这从一个字符串过滤掉“AB”的所有事件。但是,我试图将其应用于ByteString时遇到问题。

天真的版本

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

产生

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

[]显然是罪魁祸首,因为它是一个普通String不是ByteStringBS.empty中的Subbing似乎是正确的,但会给出“绑定位置中的限定名:BS.empty”。留下我们试试

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

这给出了(x cons empty)的“模式解析错误”。我真的不知道我还能在这里做什么。

作为一个方面说明,我正在尝试使用此功能是从某些文本中筛选出特定的UTF16字符。如果有一个干净的方法来实现这一点,我很乐意听到它,但这种模式匹配错误看起来像是一个新手哈克勒应该真正理解的东西。

+0

我不知道,但也许守卫,而不是模式匹配? – 2010-10-29 23:24:16

+1

您无法过滤出UTF-16字符。也许你的意思是“过滤出以UTF-16编码的文本的字符”。 – gawi 2010-10-30 00:55:23

回答

21

可以使用view patterns这样的事情

{-# 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) 
+2

bytestrings使Haskell代码看起来很难看;前奏字符串的所有优雅似乎消失:( – mntk123 2015-09-18 06:55:42

+1

@ mntk123 Haskell的字符串的字符的链接列表和非常低效的。他们仍然存在向后兼容性。字节字符串和文本包提供给了同样的问题更强大的解决方案。 – Jaseem 2016-11-01 09:25:29

10

模式使用数据构造函数。 http://book.realworldhaskell.org/read/defining-types-streamlining-functions.html

您的empty只是第一个参数的绑定,它可能是x,它不会改变任何东西。

您不能在您的模式中引用正常功能,因此(x cons empty)是不合法的。注:我猜(cons x empty)真的是你的意思,但这也是非法的。

ByteStringString完全不同。 String[Char]的别名,因此它是一个真正的列表,并且:运算符可用于模式。

ByteString是Data.ByteString.Internal.PS !(GHC.ForeignPtr.ForeignPtr GHC.Word.Word8) !Int !Int(即指向原生char * + offset + length的指针)。由于ByteString的数据构造函数是隐藏的,所以必须使用函数来访问数据,而不是模式。


这里的解决方案(当然不是最好的)使用text包您UTF-16滤波器问题:

module Test where 

import Data.ByteString as BS 
import Data.Text as T 
import Data.Text.IO as TIO 
import Data.Text.Encoding 

removeAll :: Char -> Text -> Text 
removeAll c t = T.filter (/= c) t 

main = do 
    bytes <- BS.readFile "test.txt" 
    TIO.putStr $ removeAll 'c' (decodeUtf16LE bytes) 
+0

不知道关于模式和数据构造函数的那一点。由于如下所述,ByteString不会导出其构造函数,所以现在这是有道理的。感谢所有回答。 – LOS 2010-10-30 20:58:06

6

对于这一点,对uncons :: ByteString -> Maybe (Word8, ByteString)结果我会模式匹配。

Haskell中的模式匹配只适用于用'data'或'newtype'声明的构造函数。 ByteString类型不会导出无法匹配的构造函数。

2

只是为了解决您收到的错误消息,这意味着什么:

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

因此,编译预期你的函数为类型:BS.ByteString -> BS.ByteString,因为你在签名中给了它那种类型。然而,它推断(通过看你的函数体),该函数实际上[a] -> [a]类型是。这里有一个不匹配,所以编译器抱怨。

麻烦的是你所想的(:)和[]作为语法糖,当他们实际上只是在列表类型的构造函数(这是非常不同的字节字符串)。

7

GHC(7.8)的最新版本有一个名为它可以添加到gawi的示例模板同义词功能:

{-# 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)) 

的进一步深入,你可以抽象的这对任何类型的类工作(这会看起来更好当/如果我们得到associated pattern synonyms)。该模式的定义保持不变:

-- 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)) 

而对于它的地狱:

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)) 

你可以看到

其中
{-# 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   = (:) 

情况下dropR可以同时[Word8]ByteString工作更多关于我的post模式同义词。