2010-10-29 76 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模式同義詞。