2014-05-06 6 views
3

J'essaie de créer un analyseur pour un format de fichier personnalisé. Dans le format, je travaille avec, certains champs ont une balise de fermeture comme ceci:Parsec renvoie [Char] au lieu du texte

<SOL> 
<DATE>0517 
<YEAR>86 
</SOL> 

Je suis en train de saisir la valeur entre les </ et > et de l'utiliser dans le cadre du plus grand analyseur.

J'ai trouvé le code ci-dessous. Le problème est, l'analyseur renvoie [Char] au lieu de Text. Je peux emballer chaque Char en faisant fmap pack $ return r pour obtenir une valeur de texte, mais j'espérais que l'inférence de type me sauverait de devoir faire cela. Quelqu'un pourrait-il donner des conseils pour savoir pourquoi je suis de retour [Char] au lieu de Text, et comment puis-je récupérer Text sans avoir à emballer manuellement la valeur?

{-# LANGUAGE NoMonomorphismRestriction #-} 
{-# LANGUAGE OverloadedStrings #-} 

import   Data.Text 
import   Text.Parsec 
import   Text.Parsec.Text 

-- |A closing tag is on its own line and is a "</" followed by some uppercase characters 
-- followed by some '>' 
closingTag = do 
    _ <- char '\n' 
    r <- between (string "</") (char '>') (many upper) 
    return r 

Répondre

4

string a le type

string :: Stream s m Char => String -> ParsecT s u m String 

(Voir here pour la documentation)

donc obtenir un retour String est exactement ce qui est censé se produire.

L'inférence de type ne change pas les types, elle ne fait que les inférer. String est un type concret, donc il n'y a aucun moyen d'en déduire Text pour cela.

Ce que vous pourrait faire, si vous avez besoin ce dans quelques endroits, est d'écrire une fonction

text :: Stream s m Char => String -> ParsecT s u m Text 
text = fmap pack . string 

ou même

string' :: (IsString a, Stream s m Char) => String -> ParsecT s u m a 
string' = fmap fromString . string 

En outre, il n'a pas d'importance cet exemple, mais vous voudrez probablement importer Text qualifié, des noms comme pack sont utilisés dans un certain nombre de modules différents.


Comme Ørjan Johansen a souligné à juste titre, string est pas vraiment le problème ici, est many upper. Le même principe s'applique cependant.

+2

Je pense que «beaucoup supérieur» est plus pertinent que «chaîne» ici, parce que «entre» renvoie uniquement le résultat de son troisième argument d'analyseur. –

+0

Je vois que le type 'many upper' est' ParsecT sum [Char] ' J'avais l'impression que les valeurs' [Char] 'pouvaient être utilisées comme' Text' sans avoir à les empaqueter manuellement, si l'extension OverloadedStrings a été allumé? – Arnob

+0

OverloadedString est une extension syntaxique et non une extension de type système. En particulier, il lit les littéraux de chaîne (éléments entre guillemets) comme étant dans la classe IsString. – nomen

3

La raison pour laquelle vous obtenez [Char] est que upper un Char et parse many tourne que dans un [Char]. Je voudrais écrire mon propre combinateur le long des lignes de:

manyPacked = fmap pack . many 

Vous pouvez probablement utiliser la programmation au niveau du type avec des classes de type etc. pour choisir automatiquement entre many et manyPack selon Expect type de retour, mais je ne pense que ça vaut le coup. (Cela ressemblerait probablement à CanBuiltFrom de Scala).

Questions connexes