2010-10-29 12 views
25

Ich bin ein Haskell-Neuling und habe ein bisschen Mühe herauszufinden, wie man eine ByteString gemusterte passt. Die [Char] Version meiner Funktion wie folgt aussieht:Haskell Bytestrings: Wie Muster passen?

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

Wie erwartet, diese filtert alle Vorkommen von „ab“ aus einem String. Allerdings habe ich Probleme, dies auf eine ByteString anzuwenden.

Die naive Version

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

ergibt

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

[] eindeutig der Schuldige ist, wie es für eine regelmäßige String kein ByteString ist. Subbing in BS.empty scheint wie das Richtige, aber gibt "qualifizierten Namen in der Bindungsposition: BS.empty." Verlassen uns

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

dieses „analysieren Fehler im Muster“ für (x cons empty) gibt zu versuchen. Ich weiß nicht wirklich, was ich hier noch tun kann.

Als eine Randnotiz versuche ich mit dieser Funktion ein bestimmtes UTF16-Zeichen aus einem Text herauszufiltern. Wenn es einen sauberen Weg gibt, dies zu erreichen, würde ich es gerne hören, aber dieser Muster-Übereinstimmungs-Fehler scheint etwas zu sein, was ein Neuling Hasenkeller wirklich verstehen sollte.

+0

Ich bin mir nicht sicher, aber vielleicht eher Wachen als Mustervergleich? –

+1

Sie können kein UTF-16-Zeichen ausfiltern. Vielleicht meintest du "filtere einen Charakter eines Textes aus, der in UTF-16 kodiert ist". – gawi

Antwort

21

Sie view patterns für solche Dinge verwenden können

{-# 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 machen Haskell Code so hässlich; die ganze Eleganz des Präludiums String scheint wegzugehen :( – mntk123

+1

@ mntk123 Haskell Strings sind Character Linklisten und ziemlich ineffizient. Sie bestehen immer noch für Abwärtskompatibilität. Bytestring sowie Text-Paket bieten viel leistungsfähigere Lösungen für das gleiche Problem. – Jaseem

10

Muster verwenden Datenkonstruktoren. http://book.realworldhaskell.org/read/defining-types-streamlining-functions.html

Ihre empty ist nur eine Bindung für den ersten Parameter, es hätte x sein können und es würde nichts ändern.

Sie können keine normale Funktion in Ihrem Muster referenzieren, daher ist (x cons empty) nicht zulässig. Hinweis: Ich denke (cons x empty) ist wirklich was du meintest, aber das ist auch illegal.

ByteString ist ganz anders als String. String ist ein Alias ​​von [Char], so ist es eine echte Liste und der : Operator kann in Mustern verwendet werden.

ByteString ist Data.ByteString.Internal.PS !(GHC.ForeignPtr.ForeignPtr GHC.Word.Word8) !Int !Int (d. H. Ein Zeiger auf ein natives Zeichen * + Offset + Länge). Da der Datenkonstruktor von ByteString ausgeblendet ist, müssen Sie Funktionen verwenden, um auf die Daten und nicht auf Muster zuzugreifen.


hier eine Lösung (sicherlich nicht die beste), um Ihr UTF-16 Filterproblem mit dem text Paket:

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

Wusste dieses Bit über Muster und Datenkonstruktoren nicht. Da, wie unten erwähnt, ByteString seine Konstruktoren nicht exportiert, ist dies jetzt sinnvoll. Danke an alle, die geantwortet haben. – LOS

6

Dazu würde ich Mustervergleich auf dem Ergebnis der uncons :: ByteString -> Maybe (Word8, ByteString).

Mustererkennung in Haskell funktioniert nur für Konstruktoren, die mit 'data' oder 'newtype' deklariert sind. Der ByteString-Typ exportiert seine Konstruktoren nicht, die nicht mit dem Muster übereinstimmen.

2

einfach die Fehlermeldung zu adressieren Sie erhalten haben und was es bedeutet:

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

So ist der Compiler erwartet Ihre Funktion vom Typ zu sein : BS.ByteString -> BS.ByteString weil Sie es in Ihrer Signatur eingegeben haben. Doch es geschlussfolgerten (durch Blick auf den Körper Ihrer Funktion), dass die Funktion tatsächlich vom Typ [a] -> [a] ist. Da ist ein Missverhältnis, so beschwert sich der Compiler.

Das Problem ist, dass Sie (:) und [] als syntaktischen Zucker denken, wenn sie eigentlich nur die Konstruktoren für den Listentyp sind (was SEHR anders ist als ByteString).

7

Die neueste Version von GHC (7.8) ein Merkmalsmuster Synonyme genannt, die zu GAWI dem Beispiel hinzugefügt werden können:

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

weiter gehen Sie können diese Zusammenfassung auf jede Art Klasse zu arbeiten (dies wird schöner aussehen wenn/wenn wir associated pattern synonyms bekommen). Die Musterdefinitionen bleiben gleich:

{-# 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 diesem Fall dropR sowohl [Word8] und ByteString arbeiten können:

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

Und für die Hölle davon:

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

Sie können sehen, mehr auf meinem post auf Muster Synonyme.

Verwandte Themen