parsing haskell types indentation parsec

parsing - Haskell/Parsec: cómo uso Text.Parsec.Token con Text.Parsec.Indent(del paquete de sangría)



types indentation (1)

¿Que estás tratando de hacer?

Parece que desea que sus analizadores estén definidos en todas partes como de tipo

Parser Something

(donde Something es el tipo de retorno) y para hacer que esto funcione ocultando y redefiniendo el tipo de Parser que normalmente se importa desde Text.Parsec.String o similar. Todavía necesitas importar algo de Text.Parsec.String , para hacer de Stream una instancia de una mónada; haz esto con la línea:

import Text.Parsec.String ()

Su definición de Parser es correcta. Alternativamente y de manera equivalente (para aquellos que siguen el chat en los comentarios) puede usar

import Control.Monad.State import Text.Parsec.Pos (SourcePos) type Parser = ParsecT String () (State SourcePos)

y posiblemente import Text.Parsec.Indent (IndentParser) la import Text.Parsec.Indent (IndentParser) en el archivo en el que aparece esta definición.

Error, error en la pared.

Su problema es que está viendo la parte incorrecta del mensaje de error del compilador. Te estás enfocando en

Couldn''t match expected type `State SourcePos'' with actual type `Identity''

cuando deberías centrarte en

Expected type: P.GenTokenParser ... Actual type: P.TokenParser ...

¡Se compila!

Donde "importa" los analizadores de Text.Parsec.Token , lo que realmente hace, por supuesto (como mencionó brevemente) es primero definir un registro de sus parámetros de idioma y luego pasarlo a la función makeTokenParser , que devuelve un registro que contiene los analizadores de fichas.

Por lo tanto, debes tener algunas líneas que se parezcan a esto:

import qualified Text.Parsec.Token as P beetleDef :: P.LanguageDef st beetleDef = haskellStyle { parameters, parameters etc. } lexer :: P.TokenParser () lexer = P.makeTokenParser beetleDef

... pero un P.LanguageDef st es solo una GenLanguageDef String st Identity , y un P.TokenParser () es realmente una GenTokenParser String () Identity .

Debe cambiar sus declaraciones de tipo a lo siguiente:

import Control.Monad.State import Text.Parsec.Pos (SourcePos) import qualified Text.Parsec.Token as P beetleDef :: P.GenLanguageDef String st (State SourcePos) beetleDef = haskellStyle { parameters, parameters etc. } lexer :: P.GenTokenParser String () (State SourcePos) lexer = P.makeTokenParser beetleDef

... ¡y eso es! Esto permitirá que sus analizadores de token "importados" tengan el tipo ParsecT String () (State SourcePos) Something , en lugar de Parsec String () Something (que es un alias para ParsecT String () Identity Something ) y su código debería compilarse.

(Para mayor generalidad, supongo que podría estar definiendo el tipo de Parser en un archivo separado e importado por el archivo en el que define sus funciones de analizador reales. Por lo tanto, las dos declaraciones de import repetidas).

Gracias

Muchas gracias a Daniel Fischer por ayudarme con esto.

El paquete de sangría para el Parsec de Haskell proporciona una manera de analizar lenguajes de estilo de sangría (como Haskell y Python). Redefine el tipo de Parser , así que, ¿cómo usa las funciones del analizador de tokens exportadas por el módulo Text.Parsec.Token de Parsec, que son del tipo de Parser normal?

Fondo

Parsec viene con Parsec . la mayoría de ellos exportan un montón de analizadores útiles (por ejemplo, newline de Text.Parsec.Char , que analiza una nueva línea) o combinadores de analizador (por ejemplo, count np de Text.Parsec.Combinator , que ejecuta el analizador p , n veces)

Sin embargo, el módulo Text.Parsec.Token desea exportar funciones parametrizadas por el usuario con características del lenguaje que se está analizando, de modo que, por ejemplo, la función de braces p ejecutará el analizador p después de analizar un ''{'' y antes de analizar un ''}'', ignorando cosas como comentarios, cuya sintaxis depende de su idioma.

La forma en que Text.Parsec.Token logra esto es que exporta una sola función makeTokenParser , a la que llama, dándole los parámetros de su idioma específico (como el aspecto de un comentario) y devuelve un registro que contiene todas las funciones en Text.Parsec.Token , adaptado a su idioma según lo especificado.

Por supuesto, en un lenguaje de estilo de sangría, estos deberían ser adaptados aún más (quizás? Aquí no estoy seguro, lo explicaré en un momento), así que observo que el paquete IndentParser (presumiblemente obsoleto) proporciona un módulo Text.ParserCombinators.Parsec.IndentParser.Token que parece ser un reemplazo Text.Parsec.Token para Text.Parsec.Token .

Debo mencionar en algún momento que todos los analizadores Parsec son funciones monádicas, por lo que hacen cosas mágicas con estado para que los mensajes de error puedan indicar en qué línea y columna del archivo de origen apareció el error.

Mi problema

Por un par de pequeñas razones, me parece que el paquete de sangrados es más o menos la versión actual de IndentParser, sin embargo, no proporciona un módulo que se parece a Text.ParserCombinators.Parsec.IndentParser.Token , solo proporciona Text.Parsec.Indent , así que me pregunto cómo se hace para obtener todos los analizadores de token de Text.Parsec.Token (como reserved "something" que analiza la palabra clave reservada "algo", o braces que mencioné anteriormente).

Me parece que (el nuevo) Text.Parsec.Indent funciona mediante algún tipo de magia de estado monádica para determinar en qué columna son los bits del código fuente, de modo que no es necesario modificar los analizadores de token como whiteSpace from Text.Parsec.Token , que es probablemente la razón por la que no proporciona un módulo de reemplazo. Pero estoy teniendo un problema con los tipos.

Verá, sin Text.Parsec.Indent , todos mis analizadores son de tipo Parser Something donde Something es el tipo devuelto y Parser es un alias de tipo definido en Text.Parsec.String como

type Parser = Parsec String ()

pero con Text.Parsec.Indent , en lugar de importar Text.Parsec.String , utilizo mi propia definición

type Parser a = IndentParser String () a

lo que hace que todos mis analizadores de tipo IndentParser String () Something , donde IndentParser se define en Text.Parsec.Indent. pero los analizadores de tokens que recibo de makeTokenParser en Text.Parsec.Token son del tipo incorrecto.

Si esto no tiene mucho sentido ahora, es porque estoy un poco perdido. El problema de tipo se discute un poco aquí .

El error que recibo es que he intentado reemplazar la definición de Parser anterior con la otra, pero cuando intento usar uno de los analizadores de token de Text.Parsec.Token , Text.Parsec.Token el error de compilación

Couldn''t match expected type `Control.Monad.Trans.State.Lazy.State Text.Parsec.Pos.SourcePos'' with actual type `Data.Functor.Identity.Identity'' Expected type: P.GenTokenParser String () (Control.Monad.Trans.State.Lazy.State Text.Parsec.Pos.SourcePos) Actual type: P.TokenParser ()

Campo de golf

Lamentablemente, ninguno de los ejemplos anteriores usa analizadores de token como los de Text.Parsec.Token.