2011-06-16 9 views
10

¿Qué significa la restricción (Stream s Identity t) en el siguiente tipo de declaración?La firma tipo de la función Parsec 'parse' y la clase 'Stream'

parse :: (Stream s Identity t) 
    => Parsec s() a -> SourceName -> s -> Either ParseError a 

¿Qué es Stream en la siguiente declaración de clase, qué significa? Estoy totalmente perdido.

class Monad m => Stream s m t | s -> t where 

Cuando uso Parsec, me meto en un atasco con el tipo de firmas (xxx :: yyy) todo el tiempo. Siempre omito las firmas, cargo el src en ghci y luego copio la firma de tipo a mi archivo .hs. Funciona, pero todavía no entiendo cuáles son todas estas firmas.


EDIT: más sobre el punto de mi pregunta.

Todavía estoy confundido sobre el 'contexto' del tipo de firma:

(Show a) => 

significa a debe haber una instancia de la clase Show.

(Stream s Identity t) => 

¿cuál es el significado de este 'contexto', ya que t nunca se presentó después de la =>


Tengo un montón de diferentes analizador para funcionar, así que escribir una función de urdimbre para ejecutar cualquiera de esos analizadores con archivos reales. pero aquí viene el problema:

Aquí está mi código, no se puede cargar, ¿cómo puedo hacer que funcione?

module RunParse where 
import System.IO 
import Data.Functor.Identity (Identity) 
import Text.Parsec.Prim (Parsec, parse, Stream) 

--what should I write "runIOParse :: ..." 
--runIOParse :: (Stream s Identity t, Show a) => Parsec s() a -> String -> IO() 
runIOParse pa filename = 
    do 
    inh <- openFile filename ReadMode 
    outh <- openFile (filename ++ ".parseout") WriteMode 
    instr <- hGetContents inh 
    let result = show $ parse pa filename instr 
    hPutStr outh result 
    hClose inh 
    hClose outh 
+0

¿Está declarando tipos para sus combinadores? Si no, ¿tal vez tienes errores de ambigüedad? –

Respuesta

12

la restricción: (Corriente s Identidad t) significa qué?

Esto significa que la entrada s el analizador funciona en (es decir [Char]) debe ser una instancia de la clase Stream. En el documentation verá que [Char] es de hecho una instancia de Stream, ya que cualquier lista es.

El parámetro t es el tipo de token, que normalmente es Char y es determinded por s, como indica la dependencia funcional s -> t.

Pero no se preocupe demasiado por esta clase de flujo. Se usa solo para tener una interfaz unificada para cualquier tipo de Stream, p. Ej. listas o ByteStrings.

lo que es corriente

Una secuencia es simplemente una clase de tipos. Tiene la función uncons, que devuelve el encabezado de la entrada y la cola en una tupla envuelta en Maybe. Normalmente no necesitarás esta función. Por lo que puedo ver, solo es necesario en los analizadores sintácticos más básicos como tokenPrimEx.

Editar:

¿cuál es el significado de este 'contexto', ya que t nunca se presentó después de la =>

Tenga una mirada en functional dependencies. El t nunca se muestra después de '=>', ya que está determinado por s. Y significa que puede usar uncons en lo que s es.

Aquí está mi código, no se puede cargar, ¿cómo puedo hacer que funcione?

Simple: Agregue un estado de importación para Text.Parsec.String, que define la instancia faltante para Stream [tok] m tok. La documentación podría ser un poco más clara aquí, porque parece que esta instancia se definió en Text.Parsec.Prim.

O bien, importe toda la biblioteca de Parsec (import Text.Parsec) - así es como siempre lo hago.

+0

Siento que está cerca de la respuesta, ¿Puedes explicar más sobre la estructura sintáctica de '(Identidad de Stream t)'? ¡muchas gracias! PD He editado mi pregunta. – Nybble

+0

Trató de responder a su edición. – bzn

11

La clase de tipo Stream es una abstracción para estructuras de datos similares a listas. Las primeras versiones de Parsec solo funcionaban para analizar listas de tokens (por ejemplo, String es un sinónimo de [Char], por lo que Char es el tipo de token), lo que puede ser una representación muy ineficiente. Hoy en día, la mayoría de las contribuciones importantes en Haskell se manejan como Text o ByteString, que no son listas, pero pueden ser muy parecidas a ellas.

Así, por ejemplo, se mencionan

parse :: (Stream s Identity t) 
    => Parsec s() a -> SourceName -> s -> Either ParseError a 

Algunas especializaciones de este tipo sería

parse1 :: Parsec String() a -> SourceName -> String -> Either ParseError a 
parse2 :: Parsec Text() a -> SourceName -> Text -> Either ParseError a 
parse3 :: Parsec ByteString() a -> SourceName -> ByteString -> Either ParseError a 

o incluso, si tiene un analizador léxico independiente con un tipo de token MyToken:

parse4 :: Parsec [MyToken]() a -> SourceName -> [MyToken] -> Either ParseError a 

De estos, solo el primero y el último usan listas reales para la entrada, pero el medio dos usan otras instancias Stream que actúan lo suficiente como listas para que Parsec trabaje con ellas.

Incluso puede declarar su propia instancia Stream, de modo que si su entrada está en algún otro tipo que actúa como una especie de lista, puede escribir una instancia, implementar la función uncons, y Parsec trabajará con su tipo, como bien.

Cuestiones relacionadas