2016-03-21 11 views
4

Ich bin ziemlich neu in Haskell, und mein erstes Projekt ist es, erfasste WLAN-Pakete zu parsen. Ein übliches Muster bei der Analyse eines solchen Pakets besteht darin, dass ein Header-Feld die Struktur der verbleibenden Bytes definiert. Als allgemeines Beispiel kann ein Paket wie folgt formatiert sein:Monadische Analyse von Binärdaten in Haskell

header + [payload A | payload B | ..] 

wo ein Flag-Feld (kann ein Bitmap) in dem Header angibt Welche Nutzlast (en) in dem Paket enthalten ist. Ein spezielles Beispiel für dieses Format finden Sie unter radiotap.

A similar thread schlägt vor, nur eine Folge von parse Operationen wie folgt zu verwenden:

parseAll = do 
    hdr <- parseHeader 
    pa <- parsePayloadA 
    pb <- parsePayloadB 

Allerdings scheint es nicht A und B in meinem Fall als die Existenz von Nutzlast angewendet werden, durch den Header definiert. Mit anderen Worten, der Kontrollfluss der Datenanalyse muss einem vorherigen Analyseergebnis folgen. Ich würde gerne verstehen, wenn es eine generische Möglichkeit gibt, binäre Daten mit dieser Art von Muster zu analysieren?

Antwort

2

Beachten Sie, dass parseAll eine Art von monadischen Parser-Bibliothek verwendet (wie aus der Nutzung der do Notation und die Bindungen zu sehen). Die Macht der Monaden ist genau, dass Ihre Wahl von parsePayloadA und parsePayloadB von hdr abhängen kann: Sie haben die volle Macht von Haskell, hdr zu überprüfen.

Also im Grunde kann man so etwas wie

parseAll = do 
    hdr <- parseHeader 
    payload <- case somethingInTheHdr hdr of 
     ThisIsAnA -> do 
     a <- parsePayloadA 
     return (PayloadA a) 
     ThisIsAB -> do 
     b <- parsePayloadB 
     return (PayloadB b) 
    -- can use body here, e.g. 
    return (Packet hdr payload) 

Sie haben diese Macht gerade weil in der Art der monadischen binden:

(>>=) :: m a -> (a -> m b) -> m b 

der Pfeil in a -> m b ist die wirkliche Funktion Pfeil Haskell, geben Sie alle die Macht, die Sie brauchen.

+0

Danke. Was wäre die Art von "Nutzlast" in diesem Fall? – liu3tao

+0

Vorausgesetzt, Sie haben zwei mögliche Payloads mit 'data Payload = PayloadA A | NutzlastB B' – Cactus

1

Dies ist genau der Zweck der Monad-Schnittstelle: die Abhängigkeit einer Berechnung vom Ergebnis einer vorhergehenden Berechnung zu codieren.

In Ihrem Fall wird es so etwas wie die folgenden sein:

parseAll = do 
    shouldThePayloadABeParsed <- parseHeader 
    if shouldThePayloadABeParsed 
    then do 
     pa <- parsePayloadA 
     ... 
    else do 
     pb <- parsePayloadB 
     ... 

Für Ihre Zwecke empfehle ich die "Taste of State: Parsers are Easy" Post zu lesen verstehen, wie diese Art erhalten von Werken in Haskell, und das "binary-parser" Paket Parsen um das Parsing zu machen.

Verwandte Themen