28

私は Haskell の初心者で、パターン マッチの方法を理解するのに少し苦労していByteStringます。私の関数の[Char]バージョンは次のようになります。

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ではなく通常の場合であるため、明らかに犯人ByteStringです。Subbing inBS.emptyは正しいことのように思えますが、「結合位置の修飾名: BS.empty」が表示されます。試してみましょう

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

これにより、 の「パターンの解析エラー」が発生します(x cons empty)。ここで他に何ができるか本当にわかりません。

補足として、私がこの関数でやろうとしているのは、テキストから特定の UTF16 文字を除外することです。それを達成するためのきれいな方法があれば、私はそれを聞きたいと思っていますが、このパターンマッチングエラーは初心者の haskeller が本当に理解しておくべきもののようです.

4

5 に答える 5

26

そのようなものにビューパターンを使用できます

{-# 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)
于 2010-10-30T10:14:59.573 に答える
13

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

さらに進んで、これを抽象化して任意の型クラスで動作させることができます (これは、関連付けられたパターン シノニムを取得した場合に見栄えが良くなります)。パターン定義は同じままです。

{-# 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ます。

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

パターン シノニムに関する私の投稿で詳細を確認できます。

于 2014-05-23T16:07:38.417 に答える
10

パターンはデータ コンストラクターを使用します。http://book.realworldhaskell.org/read/defining-types-streamlining-functions.html

あなたemptyは最初のパラメーターのバインディングにすぎません。それは可能であり、x何も変更されません。

パターンで通常の関数を参照することはできないため、(x cons empty)合法ではありません。注: 私(cons x empty)は本当にあなたが意図したものだと思いますが、これも違法です.

ByteStringとはかなり異なりStringます。 Stringのエイリアスで[Char]あるため、これは実際のリストであり、:演算子はパターンで使用できます。

ByteString はData.ByteString.Internal.PS !(GHC.ForeignPtr.ForeignPtr GHC.Word.Word8) !Int !Int(つまり、ネイティブ char* へのポインター + オフセット + 長さ) です。ByteString のデータ コンストラクターは非表示であるため、パターンではなく、関数を使用してデータにアクセスする必要があります。


パッケージを使用したUTF-16フィルターの問題に対する解決策(確かに最良の解決策ではありません)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)
于 2010-10-30T00:49:32.993 に答える
6

このために、 の結果に対してパターン マッチを行いuncons :: ByteString -> Maybe (Word8, ByteString)ます。

Haskell のパターン マッチングは、「data」または「newtype」で宣言されたコンストラクターでのみ機能します。ByteString 型は、パターン マッチできないコンストラクターをエクスポートしません。

于 2010-10-30T01:05:36.457 に答える
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]しました。そこに不一致があるため、コンパイラは文句を言います。

問題は、(:) と [] をシンタックス シュガーと考えていることです。これらは実際にはリスト型の単なるコンストラクターです (これは ByteString とは大きく異なります)。

于 2010-10-30T17:54:28.230 に答える