Hi. ghc -fallow-undecidable-instances -fglasgow-exts -fno-prune-tydecls -O2 \ -c -o Arglib.o Arglib.hs panic! (the `impossible' happened): mkWWcpr: not a product g{-rku-} -> (g{-rku-}, PrelMaybe.Either{-r8t,i-} ((t{-rkv-} -> tzq{-rkT-}) -> tzq{-rkT-}) [Arglib.GenArgError{-r2p,x-}]) Please report it as a compiler bug to [EMAIL PROTECTED] bye
module Arglib ( -- Grundtypen Query, Row, -- Argumentleser-Schemata Argr(..), ArgrF, ArgrC, alf, alc, -- Argumentleser Arg(..), Argn(..), Argd(..), Argnd(..), args, argns, arg_gen, argn_gen, argd_gen, argnd_gen, -- Argumentschreiber (\.), Argb(..), Argbn(..), argb2, argbn1, argbn2, argbn3, argbn4, blq, blt, -- Bausteine für generische Argumentleser GenParser(..), GenReader(..), GenWriter(..), GenNameExtractor(..), GenExtractor(..), GenArgError(..) ) where import Char import Numeric (readSigned, readDec) {-------------------------------------------------------------------------- Grundwerte --------------------------------------------------------------------------} -- Name/Wert-Liste, z.B. aus einer CGI-Abfrage type Query = [(String,String)] data QueryArgError = QueryArgError_Missing String queryGenNameExtractor :: (String -> e) -> String -> Query -> (Either String e, Query) queryGenNameExtractor mkerr name q = (case (lookupi name q) of Just val -> Left val Nothing -> Right (mkerr name), q) where lookupi _ [] = Nothing lookupi w ((x,y):li) = if (map toLower x) == (map toLower w) then Just y else lookupi w li instance GenNameExtractor Query GenArgError where genNameExtractor = queryGenNameExtractor (\name -> ArgError name "missing") instance GenNameExtractor Query QueryArgError where genNameExtractor = queryGenNameExtractor QueryArgError_Missing {- instance ToGenArgError QueryArgError where toGenArgError qae = case qae of QueryArgError_Missing str -> ArgError str "fehlt" -} -- Liste von vielleicht vorhandenen Strings, z.B. ein -- SQL-Datenbank-Abfrageergebnis mit eventuellen NULL-Werten type Row = [Maybe String] data RowArgError = RowArgError_Missing Int | RowArgError_Null Int | RowArgError_Parse Int String {- instance ToGenArgError RowArgError where toGenArgError rae = case rae of RowArgError_Missing nr -> ArgListError "zu wenige Argumente" RowArgError_Null nr -> ArgError (show nr) "unzulässiger Nullwert" RowArgError_Parse nr txt -> ArgError (show nr) ("Parsfehler bei \"" ++ txt "\"") -} instance GenExtractor Row RowArgError where genExtractor [] = (Right (RowArgError_Missing 0{---}), []) genExtractor (Nothing:xs) = (Right (RowArgError_Null 0{---}), []) genExtractor (Just str:xs) = (Left str, xs) instance GenExtractor Row GenArgError where genExtractor [] = (Right (ArgListError "zu wenige Attribute"), []) genExtractor (Nothing:xs) = (Right (ArgError "{---}" "fehlt"), []) genExtractor (Just str:xs) = (Left str, xs) instance GenNameExtractor Row RowArgError where genNameExtractor _ = genExtractor instance GenNameExtractor Row GenArgError where genNameExtractor _ = genExtractor {-------------------------------------------------------------------------- Argumentleser-Schemata --------------------------------------------------------------------------- Konstruktorklasse für Argumentlistenschemata mit folgenden Parametern: 1. der Typ der zu transformierenden Funktion 2. der Grundtyp 3. der Typ des Ergebnisses der fertig transformierten Funktion, falls alle Argumente gelesen werden konnten In einem Schema des Typs "argr a g b" enthält eine Transformierungs- funktion, die aus einer Funktion der Signatur "a1 -> a2 -> ... -> b" eine der Signatur "g -> b" macht. Dabei ist a = "a1 -> a2 -> ... -> b". b ist also ein "Suffix" von a. Das kann jedoch nicht direkt ausgedrückt werden, weil etwas der Form "x -> y" zu dem sehr verschiedenen Typ "(x1 -> x2 -> ...) -> y" führen würde. Die als a und b auftretenden Typen sind für jede konstruierte Argument- liste - und innerhalb jeder solchen - anders. Ein Argumentleserschema ist ein Typkonstruktor, und darauf ausgelegt, zusammen mit polymorphen Argumentleser-Konstruktoren und -Kombinatoren verwendet zu werden. -} class Argr argr2 where {- Kombinator für Argumentleser. Dies baut aus zwei Argumentlesern einen neuen, der die vereinten Argumente liest. Z.B. aus zwei Argumentlesern für je ein Argument einen für zwei Argumente. -} infixl 8 /. (/.) :: argr2 a b -> argr2 b c -> argr2 a c {- Eine Art Komposition eines Schemas mit einer normalen Funktion. Ein oder mehrere Argumente werden, nachdem und falls sie korrekte geparst werden konnten, nicht direkt an die zu transformierende Funktion übergeben, sondern vorher durch eine andere Funktion geleitet. Diese macht ein einziges Argument daraus, das dann übergeben wird. Ein Schema für mehrere Argumente transformiert eine mehrargumentigen Funktion eine, die diese Argumente aus dem Grundwert liest. Im Falle eines solchen wird es durch ($.) zu einem, das dieselben Argumente liest, diese jedoch der mehrargumentigen dazukomponierten Funktion übergibt. Deren eines Ergebnis wird als Argument an die Funktion weitergegeben, auf die das Schema angewendet wird. Die Komposition macht also aus einem Schema, das mehrargumentige Funktionen transforiert, eins das einargumentige transformiert. -} infix 9 $. ($.) :: f -- dazwischenzuhängende Funktion -> argr2 f v -- altes Schema -> argr2 (v -> v') v' -- neues, einargumentiges Schema --------------------------------------------------------------------------- -- Schema ArgrF -- Argumentschema zum Liefern nur des ersten Fehlers. Das Funktionsergebnis -- der transformierten Funktion besteht in entweder dem weitergereichten -- Grundwert und dem Ergebnis der transformierten Funktion oder einem -- einzelnen Fehler. newtype ArgrF g -- Grundtyp e -- Fehlertyp f -- Typ der zu transformierenden Funktionen v -- Ergebnistyp der fertig transformierten Funktion = ArgrF (f -> g -> Either (g,v) e) instance Argr (ArgrF g e) where (/.) = argrf ($.) = komp_ArgrF instance GenReader ArgrF where genReader = genReader_ArgrF -- ArgrF verwendet die generischen Argumentleser instance (GenParser t, GenExtractor g GenArgError) => Arg (ArgrF g GenArgError) t where arg = arg_gen instance (GenParser t, GenNameExtractor g GenArgError) => Argn (ArgrF g GenArgError) t where argn = argn_gen instance (GenParser t, GenExtractor g GenArgError) => Argd (ArgrF g GenArgError) t where argd = argd_gen instance (GenParser t, GenNameExtractor g GenArgError) => Argnd (ArgrF g GenArgError) t where argnd = argnd_gen -- Generischer Argumentleser für Schema ArgrF; parametrisch -- überladen im Typ des gelesenen Arguments und dem Grundtyp genReader_ArgrF :: (g -> (Either String e, g)) -> Maybe t -> (String -> Maybe t) -> Either t (String -> e) -> ArgrF g e (t -> t') t' genReader_ArgrF extr extrfb parse parsefb = ArgrF re where re fu g = bindReader extr extrfb parse parsefb g (\g' val -> Left (g', fu val)) (\_ err -> Right err) -- Argumentleser-Kombinator für ArgrF argrf :: ArgrF g e a b -> ArgrF g e b c -> ArgrF g e a c argrf (ArgrF r1) (ArgrF r2) = ArgrF (\fu g -> case r1 fu g of Left (g',fu') -> r2 fu' g' Right err -> Right err) -- Argumentleser-Komponierer für ArgrF komp_ArgrF :: f -> ArgrF g e f v -> ArgrF g e (v -> v') v' komp_ArgrF f (ArgrF re) = ArgrF (\fu g -> case re f g of Left (g', erg) -> Left (g', fu erg) Right err -> Right err) --------------------------------------------------------------------------- -- Schema ArgrC -- Argumentschema zum Liefern aller Fehler. Alle Argumente werden geparst. -- Jeder Einzelleser erzeugt eine Funktion der Art ($ x), die also eine zu -- transformierende Funktion auf ein festes Argument anwendet; sofern -- erfolgreich geparst werden konnte. Andernfalls gibt es eine Fehlerliste. -- Ein mit einer arg...-Funktion erzeugter Argumentleser wird i.A. eine nur -- einelementige Liste liefern. Der Kombinator argc vereint jedoch mehrere -- Listen. Zusätzlich wird der möglicherweise veränderte Grundwert -- weitergegeben. newtype ArgrC g -- Grundtyp e -- Fehlertyp f -- Typ der zu verarbeitenden Funktion v -- Ergebnistyp der transformierten Funktion, also f mit -- weniger Argumenten = ArgrC (g -> (g, Either (f -> v) [e])) instance Argr (ArgrC g e) where (/.) = argrc ($.) = komp_ArgrC instance GenReader ArgrC where genReader = genReader_ArgrC -- ArgrC verwendet die generischen Argumentleser instance (GenParser t, GenExtractor g GenArgError) => Arg (ArgrC g GenArgError) t where arg = arg_gen instance (GenParser t, GenNameExtractor g GenArgError) => Argn (ArgrC g GenArgError) t where argn = argn_gen instance (GenParser t, GenExtractor g GenArgError) => Argd (ArgrC g GenArgError) t where argd = argd_gen instance (GenParser t, GenNameExtractor g GenArgError) => Argnd (ArgrC g GenArgError) t where argnd = argnd_gen -- Argumentleser-Kombinator für ArgrC argrc :: ArgrC g e a b -> ArgrC g e b c -> ArgrC g e a c argrc (ArgrC r1) (ArgrC r2) = ArgrC (\g -> let (g', v') = r1 g (g'', v'') = r2 g' in (g'', case (v', v'') of (Left tr', Left tr'') -> Left (tr'' . tr') (Left _, Right errl) -> Right errl (Right errl, Left _) -> Right errl (Right errl1, Right errl2) -> Right (errl1 ++ errl2) )) -- Generischer Argumentleser für Schema ArgrC; parametrisch -- überladen im Typ des gelesenen Arguments und dem Grundtyp genReader_ArgrC :: (g -> (Either String e, g)) -> Maybe t -> (String -> Maybe t) -> Either t (String -> e) -> ArgrC g e (t -> t') t' genReader_ArgrC extr extrfb parse parsefb = ArgrC (\g -> bindReader extr extrfb parse parsefb g (\g' val -> (g', Left (\fu -> fu val))) (\g' err -> (g', Right [err]))) -- Argumentleser-Komponierer für ArgrC komp_ArgrC :: f -> ArgrC g e f v -> ArgrC g e (v -> v') v' komp_ArgrC f (ArgrC re) = ArgrC (\g -> let (g', val) = re g in (g', case val of Left tr -> Left (\f' -> f' (tr f)) Right errl -> Right errl)) {-------------------------------------------------------------------------- Generische Argumentleser --------------------------------------------------------------------------- Diese Argumentleser sind parametrisch Überladen 1. mittels Parsern für Argumenttypen 2. mittels Extrahierern für Grundtypen 3. mittels generischen Argumentlesern für Argumentschemata Auf den rechten Seiten kommen nur Typvariablen vor. Das ist normalerweise nicht erlaubt, kann aber mit -fallow-undecidable-instances zulässiggemacht werden. Siehe "http://localhost/usr.doc/ghc-4.06/docs/users_guide/users_guide/\ \multi-param-type-classes.html#AEN4641" Der Compiler schließt von argr über GenReader auf e. (?) -} arg_gen :: (GenParser t, GenExtractor g GenArgError, GenReader argr4) => argr4 g GenArgError (t -> t') t' arg_gen = genReader genExtractor Nothing genParser (Right (ArgFormatError "{---}")) argn_gen :: (GenParser t, GenNameExtractor g GenArgError, GenReader argr4) => String -> argr4 g GenArgError (t -> t') t' argn_gen name = genReader (genNameExtractor name) Nothing genParser (Right (ArgFormatError "{---}")) argd_gen :: (GenParser t, GenExtractor g GenArgError, GenReader argr4) => t -> argr4 g GenArgError (t -> t') t' argd_gen def = genReader genExtractor (Just def) genParser (Left def) argnd_gen :: (GenParser t, GenReader argr4, GenNameExtractor g GenArgError) => String -> t -> argr4 g GenArgError (t -> t') t' argnd_gen name def = genReader (genNameExtractor name) (Just def) genParser (Left def) {-------------------------------------------------------------------------- Abschließer --------------------------------------------------------------------------- Der Abschließer wendet ein Argumentschema auf eine zu transformierende Funktion an, und liefert die transformierte Funktion. Es stehen verschiedene Abschließer zur Verfügung. Der Abschließer bestimmt das verwendete Leserschema. Die transformiete Funktion ist jedoch immernoch polymorph im Grundtyp und Fehlertyp. -} {- Abschließer für ArgrF. Es wird nur der ersten Fehler geliefert, und eventuelle Überzählige Argumente werden ignoriert. -} alf :: ArgrF g e f v -> f -> (g -> (Either v e)) alf (ArgrF transff) fu g = case (transff fu) g of Left (_,erg) -> Left erg Right err -> Right err {- Abschließer für ArgrC. Es werden alle Argumente geparst, und alle auftretenden Fehler geliefert. Überzählige Argumente werden ignoriert. -} alc :: ArgrC g e f v -> f -> (g -> (Either v [e])) alc (ArgrC re) fu g = case re g of (_, Left transf) -> Left (transf fu) (_, Right errl) -> Right errl {-------------------------------------------------------------------------- Argumentleser --------------------------------------------------------------------------- Diese Argumentleser sind parametrisch für verschiedene Leserschemata, Grundtypen und Argumenttypen überladen. Bei den Schemata ist durch Instanzdeklarationen festgelegt, welche Argumentleser zusammen mit welchen Schemata verwendet werden können. -} -- Argumentleser ohne weitere Angaben -- alternativ: "class Arg argr2 where". Dann wäre arg parametrisch polymorph -- in und t. {---} class Arg argr2 t where arg :: argr2 (t -> t') t' -- Leser für Argumente mit Namen class Argn argr2 t where argn :: String -- Argumentname -> argr2 (t -> t') t' -- Leser für Argumente mit Voreinstellung ohne Namen class Argd argr2 t where argd :: t -- Voreinstellung -> argr2 (t -> t') t' -- Leser für Argumente mit Voreinstellung und Namen class Argnd argr2 t where argnd :: String -- Argumentname -> t -- Voreinstellung -> argr2 (t -> t') t' -- Argumentleser für unbenannte Argumente des Typs String, der nicht -- vorhandene in leere Strings übersetzt. Benötigt keine Überladung, weil -- er auf argd zurückgreift. args :: (Argd argr2 String) => argr2 (String -> t') t' args = argd "" -- Argumentleser für benannte Argumente des Typs String, der nicht -- vorhandene in leere Strings übersetzt. Benötigt keine Überladung, weil -- er auf argnd zurückgreift. argns :: (Argnd argr2 String) => String -> argr2 (String -> t') t' argns name = argnd name "" {-------------------------------------------------------------------------- Argumentschreiber --------------------------------------------------------------------------} (\.) :: (g -> a -> g) -> (g -> r) -> (g -> a -> r) infixr 9 \. (\.) fa fr g a = fr (fa g a) class Argb g t where argb :: g -> t -> g class Argbn g t where argbn :: String -> g -> t -> g {- Die sollten Argumentschreiber mit Null Argumenten sein, doch es gibt Probleme mit \. . -- namenlose Konstante in den Grundwert class Argcb g t where argcb :: t -> g -> g -- benannte Konstante in den Grundwert class Argcbn g t where argcbn :: String -> t -> g -> g -} instance GenWriter t => Argb Row t where argb tup t = tup ++ [Just (genWriter t)] instance GenWriter t => Argbn Query t where argbn name query t = (name, genWriter t) : query argb2 :: (Argb g t1, Argb g t2) => g -> t1 -> t2 -> g argb2 = argb \. argb argbn1 :: (Argbn g t1) => String -> g -> t1 -> g argbn1 n1 = argbn n1 argbn2 :: (Argbn g t1, Argbn g t2) => String -> String -> g -> t1 -> t2 -> g argbn2 n1 n2 = argbn n1 \. argbn n2 argbn3 :: (Argbn g t1, Argbn g t2, Argbn g t3) => String -> String -> String -> String -> g -> t1 -> t2 -> t3 -> g argbn3 n1 n2 n3 n4 = argbn n1 \. argbn n2 \. argbn n3 argbn4 :: (Argbn g t1, Argbn g t2, Argbn g t3, Argbn g t4) => String -> String -> String -> String -> g -> t1 -> t2 -> t3 -> t4 -> g argbn4 n1 n2 n3 n4 = argbn n1 \. argbn n2 \. argbn n3 \. argbn n4 blq :: (Query -> r) -> r blq f = f [] blt :: (Row -> r) -> r blt f = f [] {-------------------------------------------------------------------------- Komponenten für generische Leser --------------------------------------------------------------------------} {-------------------------------------------------------------------------- Generische Argumentparser --------------------------------------------------------------------------} class GenParser t where genParser :: String -> Maybe t instance GenParser Int where genParser = readInt instance GenParser String where genParser = Just -- Ganzzahl lesen. Sie darf ein von Leerzeichen umgeben sein. Der -- ganze String muß abgedeckt werden. readInt :: String -> Maybe Int readInt str = case readSigned readDec str of [] -> Nothing [(x,r)] -> case dropWhile isSpace r of "" -> Just x _ -> Nothing {-------------------------------------------------------------------------- Generische Argumentleser --------------------------------------------------------------------------- Dies dient zum Bauen von Schemaübergreifenden generischen Argumenlesern. Der genReader kapselt alle schemabhängigen Teile. Er nimmt weitere generische Teile, die üblicherweise in anderen Gen...-Klassen definiert sind, als Argumente. Ein Schema, das die Standard-arg...-Leserkonstruktoren verwenden will, kann einen genReader definieren, und dann bei den Arg...-Instanzdeklarationen die generischen ..._gen-Leser verwenden. Der Rückfallwert kann typischerweise sowohl ein verpackter Wert vom Typ t, der anstelle des nicht lesbaren Arguments verwendet wird, als auch ein ebenso in r verpackter Fehlerwert sein. Typparemeter: argr Argumentleser-Schema, das den generischen Leser bereitstellt r Ergebnistyp, verpackt das reguläre Ergebnis der transformierten Funktion sowie eventuelle Argumentlesefehler In t', dem "Rest", ist jedes Schema parametrisch polymorph. Im Grundtyp g und dem Typ des gelesenen Arguments t ist genReader parametrisch polymorph, weil die Funktionen zum Umgang -} {---} -- Wie wird Polymorphie hier verwendet??? {---} {- über Unterschied der folgenden zwei Definitionen klarwerden: class GenReader argr2 where genReader :: (g -> (Either String e, g)) -- Extrahierer -> Maybe t -- ggF Extrahier-Rückfallwert -> (String -> Maybe t) -- Parser -> Either t (String -> e) -- Pars-Rückfallwert -> argr2 (t -> t') t' -- Argumentleser für ein Argument -} class GenReader argr4 where genReader :: (g -> (Either String e, g)) -- Extrahierer -> Maybe t -- ggF Extrahier-Rückfallwert -> (String -> Maybe t) -- Parser -> Either t (String -> e) -- Pars-Rückfallwert -> argr4 g e (t -> t') t' -- Argumentleser für ein Argument {- Hilfsfunktion zum Bauen von genReader-Implementierungen, die das wiederkehrende Lesen des Arguments durch Extrahierer und Parser verpackt. Wenn das Extrahieren fehlschlägt, liefert der Extrahierer einen Fehler des Typs e. Für diesen Fall kann mit (Just x) ein Ersatzwert (des Typs t) für das fertig extrahierte und geparste Argument angegeben werden. Dieser wird anstelle des nicht extrahierbaren Arguments verwendet. Der Extrahierfehler wird verworfen (auch wenn es sich nicht um einen "nicht gefunden"-Fehler handelt). Der Parser liefert keinen Fehlerwert, sondern nur Nothing im Falle eines Parsfehlers. Als viertes Argument muß angegeben werden, was in diesem Fall geschehen soll. Mit (Left x) kann ein Ersatzwert angegeben werden. Alternativ ist mit (Right f) eine Funktion String -> e möglich, die aus dem extrahierten String einen Parserfehler erzeugt. Wie ein beim Lesen des Arguments aufgetretener Fehler weiter behandelt wird, ist Sache des Leserschemas. Es geschieht im vorletzten Argument von bindReader. Das drittletzte gibt an, was mit einem erfolgreich gelesenen Wert geschehen soll. Beidesmal zusammen mit dem weitergegebenen Grundwert. Die gebundenen Funktionen (valf und errf, zusammen mit dem Extrahierer) bestimmen die Typen g und e. bindReader wird in g und e so polymorph, wie diese Funktionen es sind. -} bindReader :: (g -> (Either String e, g)) -- Extrahierer -> Maybe t -- ggF Extrahierer-Rückfallwert -> (String -> Maybe t) -- Parser -> Either t (String -> e) -- Parser-Rückfallwert -> g -- gelesener Grundwert -> (g -> t -> a) -- an gelesenen Wert gebundene Funktion -> (g -> e -> a) -- an Lesefehler gebundene Funktion -> a bindReader extr extrfb parse parsefb g valf errf = let (txt_or_err, g') = extr g in case case txt_or_err of Left txt -> case parse txt of Just val -> Left val Nothing -> case parsefb of Left fbval -> Left fbval Right mkerr -> Right (mkerr txt) Right err -> case extrfb of Just val -> -- verwerfe Extrahiererfehler, verwende -- Rückfallwert Left val Nothing -> Right err of Left val -> valf g' val Right err -> errf g' err {-------------------------------------------------------------------------- Generische Argumentschreiber --------------------------------------------------------------------------} class GenWriter t where genWriter :: t -> String instance GenWriter String where genWriter = id instance GenWriter Int where genWriter = show {-------------------------------------------------------------------------- Generische Extrahierer --------------------------------------------------------------------------- Extrahierer dienen zum Entnehmen von Einzelargumenten aus Grundwerten. Diese werden verwendet, um generisch Argumentleser zu bauen. Der Grundwert wird ggF abgeändert und in geänderter Form an den nächsten Argumentleser weitergegeben. Das gilt auch, wenn kein Argument extrahiert werden konnte (weil z.B. kein passendes gefunden wurde). Extrahierer nehmen keine Rückfallwerte, weil der extrahierte String noch geparst werden muß. Einen String als Rückfallwert zu übergeben, wäre nicht sehr sinnvoll. Das heißt aber, daß eine Funktion, die generische Extrahierer verwendet, nur zwischen "Erfolg" und "irgendeinen Fehler" unterscheiden kann. Andernfalls müßte der Fehler, je nach Fehlertyp anders, untersucht werden. Die arg..._gen-Funktionen mit Extrahier- -Rückfallwert können diesen also nur bei jeglichem Extrahierfehler einsetzen. Sie können sich damit nicht auf einen "nicht gefunden"-Fall beschränken. -} {- Klasse von Grundtypen mit zugehörigem Fehlertyp für generische Extrahierer nach Name. Diese Extrahierer verwenden einen Argumentname um das Argument zu identifizieren. -} class GenNameExtractor g e where genNameExtractor :: String -- Name -> g -- Grundwert -> (Either String e, -- Inhalt, falls erfolgreich g) -- weitergegebener Grundwert {- Klasse von Grundtypen mit zugehörigen Fehlertypen für generische Extrahierer eines "ersten" Arguments -} class GenExtractor g e where genExtractor :: g -> (Either String e, -- Inhalt falls erfolgreich g) -- Weitergegebener Grundwert {-------------------------------------------------------------------------- Generische Argumentlesefehler --------------------------------------------------------------------------- Dies ist ein generischer Typ für einzelne Fehler beim Lesen einer Argumentliste. Die Festlegung einer Fehlerbehandlungsstrategie ist Sache des Schemas. Für spezielle Fehlertypen gibt es Konvertierungsfunktionen nach GenArgError. Das ermöglicht es, Argumentleser polymorph im Grundtyp zu halten, wo genauere Einzelheiten nicht benötigt werden. ArgError ist für Fehler beim Auffinden eines einzelnen Arguments, z.B. Fehlen eines Arguments mit bestimmtem Name. ArgListError ist für Fehler, die nicht einem einzelnen Argument zugeordnet werden können, z.B. überzählige Argumente oder fehlende Argumente beim Grundtyp Row. ArgFormatError ist für Parsfehler. Der String zur Angabe, bei welchem Argument der Fehler auftrat, sollte eine Indentifizierung enhalten, wie Argumentnummer oder -name, so daß ein Text "Fehler in Argument ...: ..." grammatisch korrekt wird. -} data GenArgError = ArgError -- Fehler bei einzelnem Argument String -- welches Argument String -- Beschreibung des Fehlers | ArgListError -- Fehler in der Argumentliste als Ganze String -- Beschreibung des Fehlers | ArgFormatError -- Parsfehler bei einem Argument String -- welches Argument String -- Beschreibung des Fehlers deriving Show {---} {- class ToGenArgError e where toGenArgError :: e -> GenArgError instance ToGenArgError GenArgError where toGenArgError = id -} -- Dies stellt eine Standardfunktion bereit, um aus einem (mit genParser) -- nicht parsbaren String einen Parserfehler des Typs e herzustellen. Wird -- von arg_gen und argn_gen verwendet. class GenParseError e where genParseError :: String -> e instance GenParseError GenArgError where genParseError str = ArgError "" {---} ("Fehler beim Parsen von \"" ++ str ++ "\"")