2016-03-02 2 views
0

Est-il possible de déduire le type de many1?Parsec: type intuit à partir de la chaîne analysée

MWE

module Main where 

import System.Environment (getArgs) 
import Text.ParserCombinators.Parsec 
import Data.Either (rights) 

type Vertex vertexWeight = (String, vertexWeight) 

parseVertex :: Parser (Vertex a) 
parseVertex = do 
    name <- many1 (noneOf "/") 
    char '/' 
    weight <- many1 (noneOf "\n") 
    return $ (name, weight) 

main :: IO() 
main = do 
    putStrLn $ rights $ [parse parseVertex "test" "a/2"] 

Dans l'exemple ci-dessus, je voudrais que le paramètre weight pour obtenir comme Int sorti, mais cela ne tape-chèque non.

Serait-il plus sage de représenter un sommet comme (String, String) et de définir des analyseurs pour le poids?

+0

'many1 (noneOf" \ n ") :: Chaîne d'analyseur'. Vous pouvez convertir cela en un Int de plusieurs façons - par exemple 'read <$> many1 (noneOf" \ n ") :: Parser Int' - mais notez que la chaîne analysée par' many1 (noneOf "\ n") 'pourrait ne pas être un nombre du tout. Il existe un [package] (https://hackage.haskell.org/package/parsec-numbers-0.1.0/docs/Text-ParserCombinators-Parsec-Number.html) qui fournit des analyseurs numériques pour Parsec, mais si vous le souhaitez pour rouler le vôtre, vous devrez faire quelque chose comme 'lire <$> many1 (oneOf ['0' .. '9']) :: Parser Int'. – user2407038

Répondre

1

Le type Parser (Vertex a) est un raccourci pour forall a. Parser (Vertex a), à savoir son type indique que pour le choix de a, il peut avoir le type Parser (Vertex a). Ce n'est clairement pas ce que vous voulez: vous voulez dire que parseVertex aura toujours le type Parser (Vertex a) pour certains choix de a, mais ce choix doit être fait par parseVertex, pas à son site d'appel.

Ce que vous devez faire est d'utiliser un type T tel que Parser (Vertex T) couvre toutes les valeurs de retour possibles de parseVertex. Par exemple, si vous utilisez Parser (Vertex (Either Int String)), puis parseVertex pouvez choisir en fonction des résultats de l'analyse jusqu'à présent si elle retournera quelque chose de la forme (s, Left x), ou (s, Right t), où s :: String, x :: Int et t :: String.

Bien sûr, cela signifie également que les consommateurs de parseVector doivent maintenant être en mesure de gérer les deux cas.