2016-06-10 10 views
1

Ich verwende parsec, um einige Quellcode in einem AST zu analysieren. Ich habe vor kurzem die -Wall und -W Optionen aktiviert, um "verdächtigen" Code zu fangen, und es beschwert sich über viele der the parsec-related top-level functions in this file nicht explizite Typ Erweiterungen.Verstehen von Parsec-Typ Anmerkungen

Beispiel 1

vimL = choice [ block 
       , statement 
       ] 

Die abgeleitete Typ hier ist:

vimL :: ParsecT String() Data.Functor.Identity.Identity Node 

Also, wenn ich diese Anmerkung hinzufügen, der Compiler beschwert sich über keinen Zugang zu Data.Functor.Identity.Identity, was bedeutet, ich muss import es:

import Data.Functor.Identity 

Und wenn ich das tue, kann ich si mplify die Art Anmerkung an:

vimL :: ParsecT String() Identity Node 

und der Compiler wird es noch akzeptieren. Aber ich verstehe es immer noch nicht sehr.

Beispiel 2

link = Link <$> (bar *> linkText <* bar) 
    where 
    bar  = char '|' 
    linkText = many1 $ noneOf " \t\n|" 

Die abgeleitete Typ hier ist:

link :: forall u. 
     ParsecT String u Data.Functor.Identity.Identity Node 

Aber ich kann nicht verwenden, es sei denn ich auch verwenden:

{-# LANGUAGE RankNTypes #-} 

Bitte beachte, dass ich verzichten kann damit, wenn ich die forall fallen lasse. Beide dieser Arbeit:

link :: ParsecT String u Data.Functor.Identity.Identity Node 
link :: ParsecT String u Identity Node 

Beispiel 3

string' s = mapM_ char' s >> pure s <?> s 

dieses ein abgeleiteter Typ ist:

string' :: forall s u (m :: * -> *). 
      Stream s m Char => 
      [Char] -> ParsecT s u m [Char] 

Um diese eine zu verwenden, ich brauche beides:

{-# LANGUAGE RankNTypes #-} 
{-# LANGUAGE KindSignatures #-} 

Aber wieder, wenn ich diefallen lassekann ich den Typ der folgenden vereinfachen und der Compiler noch akzeptiert es:

string' :: Stream s m Char => [Char] -> ParsecT s u m [Char] 

nicht sehr einfach, aber. Weiter zu gehen und Fallenlassen der constaint:

string' :: [Char] -> ParsecT s u m [Char] 

ich:

No instance for (Stream s m Char) arising from a use of ‘char'’ 

Ich dachte:

{-# LANGUAGE NoMonomorphismRestriction #-} 

könnte mich daran aus, aber es funktioniert nicht.

Fragen

Diese meist über den Kopf gehen, so will ich nicht blind den abgeleiteten Typ Signaturen in, ohne vorher etwas mehr Einblick zu gewinnen Paste kopieren zu. Kann jemand etwas Licht auf das werfen, was diese, die besten Methoden zum Kommentieren des Parsec-schweren Codes bedeuten, was die forall mich kauft, wenn es weggelassen werden kann, ohne irgendwelche Compilerfehler zu verursachen, und ob es irgendwelche aliasing Tricks gibt, die ich kann Anwenden, um diese lesbarer zu machen?

Antwort

2

Ich bin kein Experte mit parsec, so lasse ich jemand anderes schweres Heben tun, wenn sie die Arten erklären wollen, aber hier sind einige Gedanken:

Allgemeine Pakete versuchen freundlichen Typen Synonyme zu exportieren . In diesem Fall können Sie

type Parsec s u = ParsecT s u Identity -- in Text.Parsec.Prim 
type Parser = Parsec String()   -- in Text.Parsec.String 

verwenden, damit bekommt man vimL :: Parser Node, was mehr Sinn machen sollte - es ist ein Parser, der auf einem String ausgeführt werden kann, um ein Node zu produzieren.

forall bekommt Sie sehr wenig in diesem Zusammenhang, weshalb es freundliche Synonyme gibt, die Sie verwenden sollten. Ich wette jedoch, dass in seinen eigenen Eingeweiden parsec Gebrauch von höherrangigen Typen macht, die nicht ohne die forall ausgedrückt werden können und deshalb die Signaturen, die GHC Ihnen vorschlägt, eine explizite forall haben.

(Kurz gesagt, ist forall x. <something-with-x> die gleiche wie <some-thing-with-x> aber wenn man die forall in der Mitte der Signatur haben, werden die Dinge viel unangenehmer.)

EDIT

Einige Sachen auf parsec (from the documentation). Der Typ ParsecT s u m a repräsentiert den allgemeinsten möglichen Parser. Das Lesen der Kommentare in the source hilft.

  • s beschreibt den Stream-Typ. Ein Parser im abstrakten Sinn nimmt eine Folge von Symbolen und konvertiert sie in eine strukturierte Ausgabeform.
  • a ist der Typ des Ausgabeformulars.
  • u ist der Benutzerstatustyp. parsec verfolgt bereits einige Statusinformationen (wie Ihre Position im Text, so dass es Ihnen eine sinnvolle Syntaxfehlermeldung zurückgeben kann), so dass es sinnvoll ist, den Benutzer in einem Zustand verpacken zu lassen, den er mitnehmen möchte (es gibt ein Beispiel) davon in 2.12 Advanced: User State)
  • m ist die zugrunde liegende Monade, in der Dinge ausgeführt werden. Ich denke, dass dieser Teil offensichtlich sein wird genau dann, wenn Sie Monaden grok ...

Dann, ein paar Sonderfälle auftreten:

  • Unter m = Identity bedeutet, dass wir nicht einen monadischen Kontext der Ausführung benötigen. (Das Synonym Parsec s u a ist für diesen Fall.)
  • Unter u =() bedeutet, dass wir keine Statusinformationen speichern müssen.
  • s = String nehmen bedeutet, unseren Input (Strom) wird ein String sein. (In Verbindung mit den beiden anderen Optionen oben, ist das, was das Parser a Art Synonym für.)

Schließlich bedeutet string' :: forall s u (m :: * -> *). Stream s m Char => [Char] -> ParsecT s u m [Char], dass der Ausgang ein String = [Char] und der Benutzerstatus, monadischen Kontext und kann Eingang alles sein - vorausgesetzt, sie erfüllen einige Bedingungen, daher die Stream s m Char Einschränkung.

Diese Einschränkung Stream s m t bedeutet, dass Sie in der Lage sein müssen, den Stream-Eingangstyp s in eine m (Maybe (t,s)) zu "entfalten". Der m Teil bedeutet, dass diese in einem monadischen Kontext auftreten können Entfaltung, die Maybe Teil beschäftigt sich mit der Tatsache, dass Sie nur so lange entfalten können wie Sie eingegeben haben, ist die t Token Sie die Vorderseite des Strom auszuziehen sind, und s ist der Rest des Streams. Schließlich hat der Typ des Stream s eindeutig den Typ des Tokens t zu identifizieren herauskommen, so gibt es eine funktionale Abhängigkeit s -> t.

+0

Dies ist sehr hilfreich. 'string ':: forall su (m :: * -> *). Stream sm Char => [Char] -> Parallelabschnitt Summe [Char] '' wurde String‘:: String -> Parser String', und die meisten anderen sich mit' Parser Node', 'Parser String' oder' Parser() ' . – wincent