2017-05-30 7 views
2

Ich versuche, einen Parser für eine Datenperson (data Person) zu schreiben. Aber ich muss es in nur einer Zeile mit <$> und <*> schreiben und ich habe viel versucht, aber ich werde wirklich "überfordert".Einen Parser für Personen in haskell schreiben

Der Parser-Typ ist wie üblich:

newtype Parser a = Parser (String -> [(a,String)])

Und ich habe diese Funktion:

parse :: Parser a -> String -> Maybe a

, die die erste vollständige Parse zurückgibt.

z.B.

wenn ich diese einfache Funktion habe:

upper :: Parser Char 
upper = satisfy isUpper 

Wenn ich parse upper "A" laufen bekomme ich Just 'A'

ich auch eine witzige Funktion wie diese:

name :: Parser String 
name = (:) <$> (satisfy isUpper) <*> (many $ satisfy isAlpha) 

die, wie Sie kann sehen, akzeptiert alle Zeichenfolgen, die Literalzeichen sind und mit einem höheren Buchstaben beginnen.

so:

*Main> parse name1 "hello" 
Nothing 
*Main> parse name1 "Hello" 
Just "Hello" 

Bis jetzt ist alles in Ordnung, das einzige Problem ist, dass ich für die Klasse, so etwas tun (Daten, Typ?!) Person (data Person)

so ich habe dies:

data Person = Person String deriving (Eq, Show)

Und dann, in nur einer Zeile, ich habe den Parser für Person schreiben , aber der Name sollte die Funktion name erfüllen, es bedeutet, der Name sollte nur eine Kette von literalen Zeichen sein, wobei der erste Großbuchstabe ist.

Und es sollte so funktionieren:

> parse parserPerson "Chuck" 
Just (Person "Chuck") 
> parse parserPerson "chuck" 
Nothing 

wo:

parserPerson :: Parser Person 
parserPerson = ??? 

Wie Sie sehen können, Bevor "Chuck" ist Person, also habe ich irgendwie *> zu verwenden, um es zu bekommen .

Und das ist es, nur eine Linie mit <$>, <*> und *>, die so funktioniert.

Ich habe keine Ahnung, und ich bin verrückt danach. Vielleicht könnte mir jemand helfen.

EDIT

satisfy :: (Char -> Bool) -> Parser Char -- parse a desired character 
satisfy p = Parser check 
    where 
    check (c:s) | p c = [(c,s)] -- successful 
    check _ = [  ] -- no parse 

und many (als some) Funktionen aus der Control.ApplicativeControl.Applicative

+0

Was sind 'satisfy' und' many'? – syntagma

+0

oh ja, tut mir leid. Ich schreibe es jetzt. –

+1

Unter der Annahme, dass Ihr Parser eine Funktorinstanz hat, sollten Sie in der Lage sein, 'parsePerson = Person <$> name' – tsorn

Antwort

1

Wie tsorn sagte, die Antwort war einfach ...

parserPerson :: Parser Person 
parserPerson = Person <$> name1 

und Es funktioniert, weil die Functor Instacnce definiert wurde.

instance Functor Parser where 
    fmap f (Parser p) = Parser $ \s -> map (\(a,b) -> (f a, b)) $ p s 
+1

Der Schlüssel hier ist zu erkennen, dass "Person" sowohl ein Typ als auch ein Datenkonstruktor ist, wobei letzterer nur eine Funktion ist, die ein String-Argument akzeptiert und einen Wert vom Typ Person zurückgibt. Es kann sinnvoll sein, stattdessen den Datentyp zu definieren: 'data Person = MkPerson String', wobei 'MkPerson' eine Funktion ist, die ein string-Argument akzeptiert und einen Wert vom Typ' Person' zurückgibt. – tsorn

+0

Danke, Alter! Und zum Beispiel, wenn Person '' 'Person String Int''' wäre, wie sollte ich tun, um die Zeichenfolge und die Int zu nehmen? Ich meine, ich kann einen anderen Parser für Numbers haben, aber wie funktioniert es? damit? : '' 'Person <$> Name <*> NummerParser'''? Ich wollte nur ein wenig "tiefer" in Haskell gehen und ich habe ein paar Probleme: D –

+0

Ja, das ist der richtige Ansatz. Es beruht auf der Anwendungsinstanz. – tsorn

Verwandte Themen