Pregunta

Soy un novato Haskell, y teniendo un poco de problemas para encontrar la manera de patrón coincide con un ByteString. La versión [Char] de mis miradas de función como:

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

Como era de esperar, que excluye todo ocurrencias de "ab" de una cadena. Sin embargo, no tengo problemas tratando de aplicar esto a un ByteString.

La versión ingenua

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

rendimientos

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

[] es claramente el culpable, como lo es para un String no regular de un ByteString. Reemplazando en BS.empty parece que lo correcto, pero da "Nombre calificado en la posición de encuadernado: BS.empty." dejándonos a tratar

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

esto da "error de análisis en el patrón" para (x cons empty). Realmente no sé qué más puedo hacer aquí.

Como nota al margen, lo que estoy tratando de hacer con esta función es filtrar un carácter específico UTF16 de algún texto. Si hay un camino limpio para lograr eso, me encantaría escucharlo, pero este patrón de error a juego parece como algo que un novato haskeller debe entender realmente.

¿Fue útil?

Solución

Se puede usar vista patrones para este tipo de cosas

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

Otros consejos

La última versión de GHC (7.8) tiene una característica llamada sinónimos patrón que puede ser añadido al ejemplo de 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))

El ir más allá, puede abstracta que esto funcione en cualquier tipo de clase (esto se verá mejor cuando / si conseguimos sinónimos patrón asociado ). Las definiciones de patrones permanecen igual:

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

en cuyo caso dropR puede trabajar en ambos [Word8] y 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))

Y para el placer de hacerlo:

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

Se puede ver más en mi posterior en sinónimos de patrones.

patrones de uso de constructores de datos. http://book.realworldhaskell.org/read/defining-types-streamlining -functions.html

Su empty es sólo un enlace para el primer parámetro, que podría haber sido x y no cambiaría nada.

No se puede hacer referencia a una función normal en su patrón de modo (x cons empty) no es legal. Nota: supongo (cons x empty) es realmente lo que quería decir, pero esto también es ilegal.

ByteString es bastante diferente de String. String es un alias de [Char], por lo que es una lista real y el operador : se puede utilizar en los patrones.

ByteString es Data.ByteString.Internal.PS !(GHC.ForeignPtr.ForeignPtr GHC.Word.Word8) !Int !Int (es decir, un puntero a un char nativo * + offset + longitud). Desde el constructor de datos de ByteString se oculta, debe utilizar funciones para acceder a los datos, no patrones.


A continuación, una solución (sin duda no es el mejor) a su problema filtro de UTF-16, utilizando el paquete 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)

Para esto, el ajuste de patrones haría en el resultado de uncons :: ByteString -> Maybe (Word8, ByteString).

La concordancia de patrones en Haskell sólo funciona en constructores declaradas con 'datos' o 'newtype.' El tipo ByteString no exporta sus constructores no se puede coincidencia de patrón.

Sólo para dirigir el mensaje de error recibido y lo que significa:

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

Así que el compilador espera su función a ser de tipo: BS.ByteString -> BS.ByteString ya que le dio ese tipo en su firma. Sin embargo, inferido (mirando el cuerpo de su función) que la función es en realidad el tipo de [a] -> [a]. Hay una falta de coincidencia no lo que el compilador se queja.

El problema es que usted está pensando (:) y [] como el azúcar sintáctica, cuando en realidad son sólo los constructores para el tipo de lista (que es muy diferente de ByteString).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top