2010-10-29 35 views
25

Tôi là người mới sử dụng Haskell và gặp một chút rắc rối khi tìm ra cách tạo mẫu khớp với ByteString. Phiên bản [Char] của chức năng của tôi trông giống như:Haskell Bytestrings: Cách so khớp mẫu?

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

Như mong đợi, điều này lọc ra tất cả các lần xuất hiện của "ab" từ một chuỗi. Tuy nhiên, tôi gặp sự cố khi cố gắng áp dụng điều này cho một số ByteString.

Phiên bản ngây thơ

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

mang

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

[] rõ ràng là thủ phạm, vì nó là một thường xuyên String không phải là một ByteString. Subbing trong BS.empty có vẻ như là điều đúng nhưng cung cấp cho "Tên đủ điều kiện ở vị trí ràng buộc: BS.empty." Để chúng tôi thử

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

điều này cho phép "phân tích lỗi trong mẫu" cho (x cons empty). Tôi thực sự không biết mình có thể làm gì khác ở đây.

Lưu ý phụ, những gì tôi đang cố gắng làm với chức năng này là lọc ra một ký tự UTF16 cụ thể từ một số văn bản. Nếu có một cách sạch sẽ để thực hiện điều đó, tôi rất muốn nghe nó, nhưng lỗi kết hợp mẫu này có vẻ giống như một cái gì đó mà một người mới bắt đầu phải thực sự hiểu.

+0

Tôi không chắc chắn, nhưng có thể bảo vệ hơn là khớp mẫu? –

+1

Bạn không thể lọc ra một ký tự UTF-16. Có lẽ bạn có nghĩa là "lọc ra một ký tự của một văn bản được mã hóa bằng UTF-16". – gawi

Trả lời

21

Bạn có thể sử dụng view patterns cho những thứ như vậy

{-# 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 làm cho mã Haskell trông rất xấu xí; tất cả sự tao nhã của prelude String dường như biến mất: ( – mntk123

+1

@ mntk123 Chuỗi Haskell là danh sách liên kết ký tự và khá kém hiệu quả. Chúng vẫn tồn tại cho khả năng tương thích ngược. – Jaseem

10

Các mẫu sử dụng trình tạo dữ liệu. http://book.realworldhaskell.org/read/defining-types-streamlining-functions.html

empty của bạn chỉ là một ràng buộc cho tham số đầu tiên, có thể là x và nó sẽ không thay đổi bất cứ điều gì.

Bạn không thể tham chiếu chức năng bình thường trong mẫu của mình để (x cons empty) không hợp pháp. Lưu ý: Tôi đoán (cons x empty) thực sự là ý của bạn nhưng điều này cũng bất hợp pháp.

ByteString hoàn toàn khác với String. String là bí danh của [Char], vì vậy đây là danh sách thực và toán tử : có thể được sử dụng trong các mẫu.

ByteString là Data.ByteString.Internal.PS !(GHC.ForeignPtr.ForeignPtr GHC.Word.Word8) !Int !Int (tức là con trỏ đến độ dài gốc * + bù +). Vì hàm tạo dữ liệu của ByteString bị ẩn, bạn phải sử dụng các hàm để truy cập dữ liệu chứ không phải các mẫu.


Dưới đây là một giải pháp (chắc chắn không phải là tốt nhất) cho vấn đề lọc UTF-16 của bạn bằng cách sử dụng gói text:

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

Không biết chút nào về các mẫu và các nhà xây dựng dữ liệu. Vì, như đã lưu ý dưới đây, ByteString không xuất các nhà xây dựng của nó, điều này có ý nghĩa bây giờ. Cảm ơn tất cả những ai đã trả lời. – LOS

6

Đối với điều này, tôi sẽ mô hình phù hợp vào kết quả của uncons :: ByteString -> Maybe (Word8, ByteString).

Đối sánh mẫu trong Haskell chỉ hoạt động trên các hàm tạo được khai báo với 'dữ liệu' hoặc 'kiểu mới'. Loại ByteString không xuất các hàm tạo của nó, bạn không thể khớp mẫu.

2

Chỉ cần để giải quyết được thông báo lỗi mà bạn nhận được và những gì nó có nghĩa là:

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

Vì vậy, trình biên dịch dự kiến ​​ chức năng của bạn để được các loại : BS.ByteString -> BS.ByteString vì bạn đã cho nó loại chữ ký của bạn. Tuy nhiên, nó phỏng đoán (bằng cách nhìn vào phần thân của hàm của bạn) rằng hàm này thực sự thuộc loại [a] -> [a]. Có một sự không phù hợp ở đó để trình biên dịch phàn nàn.

Vấn đề là bạn đang nghĩ đến (:) và [] là đường cú pháp, khi chúng thực ra chỉ là các hàm tạo cho kiểu danh sách (VERY khác với ByteString).

7

Phiên bản mới nhất của GHC (7.8) có một tính năng gọi là từ đồng nghĩa mô hình có thể được thêm vào ví dụ gawi của:

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

Hơn thế nữa bạn có thể trừu tượng này để làm việc trên bất kỳ lớp kiểu (điều này sẽ trông đẹp hơn khi/nếu chúng tôi nhận được associated pattern synonyms). Các định nghĩa mô hình giữ nguyên:

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

trong trường hợp dropR có thể làm việc trên cả hai [Word8]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)) 

Và đối với những địa ngục của nó:

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

Bạn có thể thấy nhiều hơn trên số post của tôi trên các từ đồng nghĩa mẫu.

Các vấn đề liên quan