Überprüfen Sie das Modul Control.Arrow.Transformer.Automaton im Paket "arrows".Der Typ sieht so aus:
newtype Automaton a b c = Automaton (a b (c, Automaton a b c))
Dies ist ein bisschen verwirrend, weil es ein Pfeil Transformator ist. Im einfachsten Fall können Sie schreiben
type Auto = Automaton (->)
Welche Funktionen als zugrunde liegenden Pfeil verwendet. Setzt man (->) für „a“ in der Automaton Definition und Infix-Notation können Sie sehen, dies entspricht in etwa:
newtype Auto b c = Automaton (b -> (c, Auto b c))
Mit anderen Worten: ein Automat ist eine Funktion, die eine Eingabe nimmt und gibt ein Ergebnis zurück und ein neuer Automat.
Sie können dies direkt verwenden, indem Sie eine Funktion für jeden Zustand schreiben, der ein Argument akzeptiert und das Ergebnis und die nächste Funktion zurückgibt. Zum Beispiel ist hier eine Zustandsmaschine, um das Regexp "a + b" zu erkennen (dh eine Folge von mindestens einem "a", gefolgt von einem "b"). (Anmerkung: ungetestet Code)
state1, state2 :: Auto Char Bool
state1 c = if c == 'a' then (False, state2) else (False, state1)
state2 c = case c of
'a' -> (False, state2)
'b' -> (True, state1)
otherwise -> (False, state1)
In Bezug auf Ihre ursprüngliche Frage, Q = {state1, state2}, X = Char, Delta-Funktion Anwendung und F ist der Zustandsübergang Rückkehr True (eher als ein mit "accepting state" Ich habe einen Ausgabeübergang mit einem akzeptierenden Wert verwendet.
Alternativ können Sie die Pfeilnotation verwenden. Automaton ist eine Instanz aller interessanten Pfeilklassen, einschließlich Loop und Circuit, sodass Sie mithilfe von Delay auf vorherige Werte zugreifen können. (Anmerkung: wieder, ungetesteten Code)
recognise :: Auto Char Bool
recognise = proc c -> do
prev <- delay 'x' -< c -- Doesn't matter what 'x' is, as long as its not 'a'.
returnA -< (prev == 'a' && c == 'b')
Der „Verzögerung“ bedeutet, dass Pfeil „prev“ gleich den vorherigen Wert von „c“ eher als der aktuellen Wert. Sie können mit "rec" auch auf Ihre vorherige Ausgabe zugreifen. Hier ist zum Beispiel ein Pfeil, der Ihnen im Laufe der Zeit eine verfallende Gesamtsumme gibt. (In diesem Fall tatsächlich getestet)
-- | Inputs are accumulated, but decay over time. Input is a (time, value) pair.
-- Output is a pair consisting
-- of the previous output decayed, and the current output.
decay :: (ArrowCircuit a) => NominalDiffTime -> a (UTCTime, Double) (Double, Double)
decay tau = proc (t2,v2) -> do
rec
(t1, v1) <- delay (t0, 0) -< (t2, v)
let
dt = fromRational $ toRational $ diffUTCTime t2 t1
v1a = v1 * exp (negate dt/tau1)
v = v1a + v2
returnA -< (v1a, v)
where
t0 = UTCTime (ModifiedJulianDay 0) (secondsToDiffTime 0)
tau1 = fromRational $ toRational tau
Hinweis, wie der Eingang auf „Verzögerung“ umfaßt „v“ einen Wert von seinem Ausgang abgeleitet. Der "rec" -Klausel ermöglicht dies, so dass wir eine Rückkopplungsschleife aufbauen können.
Bei einem deterministischen Automaten könnte Delta des Typ Q sein -> X -> X - -> Q Im Fall eines nicht-deterministischen Automaten, ich so etwas wie Q wählen würde> [Q] –
Was Sven Hager sagt, und 'F' könnte als' isEnd :: Q -> Bool' implementiert werden. –