2016-11-14 1 views
0

ein Datentyp data CI = CI Int Int, die eine komplexe Zahl gegeben, möchte ich einen Parser für CI bauen, die "a" zu CI a 0 und "(a,b)" zu CI a b umwandeln kann. Zum Beispiel möchte ich eine Funktion parseCI wie runParser parseCI "(1,2)" gibt den Wert [(CI 1 2, "")] (im Idealfall, aber etwas ähnliches ist in Ordnung). Ich möchte CI auch eine Instanz von read machen.Parsing eine komplexe Zahl von Scratch

Ich möchte dies mit Funktionen und Definitionen aus dem unten stehenden Code tun (im Grunde ohne etwas fortgeschrittenes, wie Parsec), aber ich bin mir nicht sicher, wo ich anfangen soll. Irgendein Startcode, um mich auf die richtige Spur und/oder einen Hinweis zu setzen, wäre hilfreich. Ich suche keine vollständige Antwort, da ich das selbst herausfinden möchte.

module Parser where 
import Control.Applicative 
import Control.Monad 

newtype Parser a = Parser { runParser :: String -> [(a,String)] } 

satisfy :: (Char -> Bool) -> Parser Char 
satisfy f = Parser $ \s -> case s of 
    [] -> [] 
    a:as -> [(a,as) | f a] 

char :: Char -> Parser Char 
char = satisfy . (==) 

string :: String -> Parser String 
string str = Parser $ \s -> [(t,u) | let (t,u) = splitAt (length str) s, str == t] 

instance Functor Parser where 
    fmap f p = Parser $ \s -> 
     [ (f a,t) 
     | (a,t) <- runParser p s 
     ] 

instance Applicative Parser where 
    pure a = Parser $ \s -> [(a,s)] 
    af <*> aa = Parser $ \s -> 
     [ (f a,u) 
     | (f,t) <- runParser af s 
     , (a,u) <- runParser aa t 
     ] 

instance Alternative Parser where 
    empty = Parser $ \s -> [] 
    p1 <|> p2 = Parser $ (++) <$> runParser p1 <*> runParser p2` 

instance Monad Parser where 
    return = pure 
    ma >>= f = Parser $ \s -> 
     [ (b,u) 
     | (a,t) <- runParser ma s 
     , (b,u) <- runParser (f a) t 
     ] 

instance MonadPlus Parser where 
    mzero = empty 
    mplus = (<|>) 
+0

Technisch gesehen, das ist eine Gauß-Nummer/nitpick. – ThreeFx

Antwort

2

Sie haben wahrscheinlich bereits gesehen, aber falls Sie nicht haben: Monadic Parsing in Haskell setzt sich wie diese Parsen.

Da Sie haben zwei verschiedene Arten von CI Parsen, könnte man dies als zwei Probleme nähern wollen: machen einen Parser parseCI1 die "a" zu CI a 0 und machen einen weiteren Parser parseCI2 die "(a,b)" zu CI a b parst analysiert. Dann können Sie diese in eine mit

parseCI = parseCI1 <|> parseCI2 

Für beide subparsers kombinieren können, werden Sie einen Weg Parsen ganzen Zahlen müssen: parseInt :: Parser Int. Wenn Sie parseInt erstellen, werden Sie wahrscheinlich eine Kombination aus satisfy, isDigit, read und möglicherweise some verwenden wollen (je nachdem, wie Sie das Problem lösen möchten).


machen CI eine Instanz von Lese etwas einfacher ist, wenn Sie parseCI getan haben:

instance Read CI where 
    readsPrec _ = runParser parseCI 
Verwandte Themen