2012-10-25 2 views
9

quelqu'un peut-il m'aider à comprendre comment utiliser le style Applicative pour écrire parseurs Parsec? Voici le code que j'ai:Parsec et le style Applicative

module Main where 
import Control.Applicative hiding (many) 
import Text.Parsec 
import Data.Functor.Identity 
data Cmd = A | B deriving (Show) 

main = do 
    line <- getContents 
    putStrLn . show $ parseCmd line 

parseCmd :: String -> Either ParseError String 
parseCmd input = parse cmdParse "(parser)" input 

cmdParse :: Parsec String() String 
cmdParse = do 
    slash <- char '/' 
    whatever <- many alphaNum 
    return (slash:whatever) 

cmdParse2 :: String -> Parsec String() String 
cmdParse2 = (:) <$> (char '/') <*> many alphaNum 

mais lorsque je tente de le compiler, je me suivant:

/home/tomasherman/Desktop/funinthesun.hs:21:13: 
    Couldn't match expected type `Parsec String() String' 
       with actual type `[a0]' 
    Expected type: a0 -> [a0] -> Parsec String() String 
     Actual type: a0 -> [a0] -> [a0] 
    In the first argument of `(<$>)', namely `(:)' 
    In the first argument of `(<*>)', namely `(:) <$> (char '/')' 
Failed, modules loaded: none. 

L'idée est que je veux cmdParse2 faire même chose qui fait cmdParse, mais en utilisant choses d'application ... mon approche est probablement complètement faux, je suis nouveau à haskell

+0

Votre erreur est comme si vous aviez écrit '(++) <$> ...' 'pas (:) <$> ...'. – huon

+0

désolé, corrigé .. je l'essayais à la fois ++ et: et je l'ai mélangé – Arg

+4

Le final dans les questions bien documentées, parce que la réponse est "Bien fait, choix du son, fait correctement, mais corriger cette erreur de type mineur " +1 – AndrewC

Répondre

4

Votre utilisation applicative est sur place, vous avez juste une signature incorrecte. Essayez:

cmdParse2 :: Parsec String() String 
+1

stupide moi, merci – Arg

+0

juste une question rapide, est-il possible d'obtenir le texte de type 'many alphaNum'? donc je ne l'emballe pas toujours manuellement si je veux utiliser le texte au lieu de la chaîne? – Arg

+0

@Arg 1. Oui. Vous pouvez convertir: '(pack <$> beaucoup alphaNum)', mais vous aurez besoin de tout convertir: 'cmdParse3 = contre <$> char '/' <*> (pack <$> beaucoup alphaNum)' mais c'est mieux écrit 'cmdParse4 = pack <$> cmdParse2' , et cela pourrait être mieux, en fonction de votre application, de le laisser jusqu'à la fin et faire «pack <$> myTopLevelParser». (Vous pourriez être intéressé par 'Text.Parsec.Text' pour changer les données source aussi.) 2. Pourquoi? Vous construisez des cordes un personnage à la fois, en les combinant de la bonne façon. 'append' est _O (n) _ pour le texte de toute façon. – AndrewC

4

Votre approche me semble correcte, le problème est que cmdParse2 a le mauvais type. Il devrait avoir le même type que cmdParse. En passant, vous pouvez omettre les parens autour de char '/' dans l'analyseur de style applicatif.

+0

cool, merci pour la pointe parens – Arg