2017-06-21 3 views
-1

Je ne comprends pas ce que fait le type de (par exemple) eol moyenne:mégaparsec: comment déclarer le type de `eol` pour analyser le texte et non [Char]

eol :: (MonadParsec e s m, Token s ~ Char) => m String 

ou, mieux, Je ne comprends pas comment utiliser eol avec Text.Megaparsec.Text et pas Text.Megaparsec.String. J'ai essayé d'apprendre à utiliser Megaparsec suite au (ancien) tutoriel pour Parsec de Real World Haskell (j'ai d'abord commencé par lire le tutoriel RWH avant de découvrir que Megaparsec existait). J'ai réécrit le code of the first example pour utiliser Megaparsec (voir ci-dessous). Mais j'ai trouvé que quand j'essaye de forcer le type de eol à Parser Text le compilateur jette l'erreur: Couldn't match type ‘[Char]’ with ‘Text’, ce que je comprends de ceci est que je ne peux pas utiliser eol avec Text ou, plus probablement, je ne sais pas comment changer cela Token s ~ Char contexte de la déclaration eol pour utiliser Token Text.

{-# LANGUAGE OverloadedStrings #-} 
{-# LANGUAGE NoImplicitPrelude #-} 

module CSVParser (
    module CSVParser 
) where 

import Foundation 
import Data.Functor.Identity (Identity) 
import Text.Megaparsec 
import Text.Megaparsec.Text 
import Data.Text 

csvFile :: Parser [[Text]] 
csvFile = 
    do result <- many line 
     eof 
     return result 

line :: Parser [Text] 
line = 
    do result <- cells 
     --eol :: Parser Text -- uncommenting this line results in a compilation error 
     eol 
     return result 

cells :: Parser [Text] 
cells = 
    do first <- cellContent 
     next <- remainingCells 
     return (first : next) 

remainingCells = 
    (char ',' >> cells) 
    <|> return [] 

cellContent :: Parser Text 
cellContent = fromList <$> many (noneOf [',','\n']) 

parseCSV :: Text -> Either (ParseError (Token Text) Dec) [[Text]] 
parseCSV = parse csvFile "(unknown)" 
+0

Pourquoi vous écrivez 'EOL :: Parser Text' quand vous ne tenez pas compte de son retour valeur quand même? –

+0

Eh bien, je le fais parce que je veux savoir comment changer son type. Je veux changer son type parce que beaucoup d'autres fonctions dans la bibliothèque ont la même déclaration de type, prennent par exemple 'lowerChar :: (MonadParsec esm, Token s ~ Char) => m Char', je peux vouloir ne pas ignorer sa valeur de retour mais contraint à être "Texte" (pour cela je pourrais faire 'fromList <$> lowerChar', mais cela semble moche, je suppose que je pourrais juste changer le type directement, mais je ne sais pas, ou ne comprends pas, comment). Principalement mon problème est avec '(MonadParsec e s m, Token s ~ Char) => m Char'. – helq

Répondre

3

Dans le type:

eol :: (MonadParsec e s m, Token s ~ Char) => m String 

la ~ est une contrainte d'égalité de type, et les MonadParsec et Token sont définis par classes de types mégaparsec. Ils peuvent être grossièrement interprétés comme suit:

  • MonadParsec e s m est une affirmation de ce type m est un analyseur monadique qui lit un Stream de type s et représente les erreurs en utilisant un ErrorComponent de type e
  • Token s est le type sous-jacent les jetons lus à partir de flux s

Ainsi, le type complet peut être interprété comme: eol est un analyseur monadique avec « valeur de retour » String qui analyse un flux dont les jetons sont Char.

Pour votre problème, la plupart de ceci peut être ignoré. La question que vous utilisez en est que eol retourne une valeur String à la suite de l'analyse syntaxique, et un String n'est pas un Text, donc vous ne pouvez pas faire un eol (qui est de type Parser String) soit de type Parser Text, peu importe comment vous essayez.

Deux solutions sont d'ignorer la valeur String de retour non désiré ou, si vous en avez besoin sous forme de texte, le convertir:

Data.Text.pack <$> eol 
+0

Merci pour l'explication sur '~', ça m'a vraiment aidé. J'ai supposé que le type 'Parsec Dec Text' (écrit comme' Parser' lors de l'importation 'Megaparsec.Text') conditionnait la sortie de 'eol' à' Text', alors qu'en réalité elle ne fait qu'appliquer 'Text' comme flux INPUT de' eol', donc le type de 'eol' dans mon exemple (code) serait 'Parsec Dec Text [Char]'. Mais je voulais obtenir 'Parsec Dec Text Text' qui est clairement impossible! parce que 'eol' a le type' (contrainte) => m [Char] === Parsec e s [Char] '. – helq

+0

Btw, j'ai aussi appris que 'Token Text == Char', que je ne m'attendais pas! parce que j'ai vu 'Text' et' [Char ]' comme des choses différentes (et elles sont, '[Char]' est une liste chaînée, et 'Text' quelque chose d'autre) mais n'ont jamais pensé à leurs parties constituantes, qui sont juste' Char 's. Il est logique maintenant, 'Parsec Dec Text [Char]' est un type totalement valide pour 'eol', je pensais que ce n'était pas parce que' Text! = [Char] ', mais il est juste en prenant' eol: : (MonadParsec esm, Token s ~ Char) => m [Char] 'et en remplaçant' e' par 'Dec',' s' par 'Text' (qui remplit' Token s ~ Char'!) Nous donne une validité totale type. – helq