Frage

Ich versuche, ein kleines Skript, das Parsen zu schreiben und Brainfuck-Code ausführt, die GHC Möglichkeiten der Optimierung zu verstehen, ich versuche, den Code zu optimieren, um ein bisschen schneller zu sein und zu verstehen, was dort vor sich geht.

Auf der Teile ist die interne represantation von BF-Code, ich einen speziellen Datentyp für diese. Hier ist der Sourcecode, die beiden Funktionen enthalten, die die Umwandlungen tun:

data BFinstruction
  = AdjustValue Int
  | MovePointer Int
  | GetChar
  | PutChar
  | Loop BFcode
  deriving (Eq)

type BFcode = [BFinstruction]

unsafeCompileBrainfuck :: String -> BFcode
unsafeCompileBrainfuck = fst . parse [] where
  -- arguments: input string, built code; output: output code, rest of input
  parse :: BFcode -> String -> (BFcode,String)
  parse c ('+':s) = parse (AdjustValue   1 :c) s
  parse c ('-':s) = parse (AdjustValue (-1):c) s
  parse c ('>':s) = parse (MovePointer   1 :c) s
  parse c ('<':s) = parse (MovePointer (-1):c) s
  parse c ('.':s) = parse (PutChar         :c) s
  parse c (',':s) = parse (GetChar         :c) s
  parse c (']':s) = (reverse c, s)
  parse c ('[':s) = parse (Loop l          :c) s' where (l,s') = parse [] s
  parse c []      = (reverse c ,"")
  parse c ( _ :s) = parse                   c  s

simplifyBrainfuck :: BFcode -> BFcode
simplifyBrainfuck ((AdjustValue x):(AdjustValue y):zs) = if x + y /= 0
  then simplifyBrainfuck (AdjustValue (x + y):zs)
  else simplifyBrainfuck zs
simplifyBrainfuck ((MovePointer x):(MovePointer y):zs) = if x + y /= 0
  then simplifyBrainfuck (MovePointer (x + y):zs)
  else simplifyBrainfuck zs
simplifyBrainfuck (x                              :zs) = x: simplifyBrainfuck zs
simplifyBrainfuck []                                   = []

Die Idee ist, dass der Code von einem Eingang (String) gelesen werden, preparsed und durch den obigen Code vereinfacht und dann durch einige andere Funktionen ausgeführt. (Es wird angenommen, dass die Eingabe gültig ist).

Um dieses Beispiel zu optimieren, habe ich versucht, den Int params des MovePointer und AdjustValue Konstrukteurs unbox von domething wie dies zu tun:

data BFinstruction -- BangPatterns
  = AdjustValue {-# UNPACK #-} !Int
  | MovePointer {-# UNPACK #-} !Int
  | GetChar
  | PutChar
  | Loop BFcode
  deriving (Eq)

Dies wird die Box Int Typ in einen unboxed, roh Int# Art drehen, das ist eine Implementierung Detail GHc. Wie ich gelesen habe, ist diese Option nur gut in wenigen Fällen, so möchte ich fragen, von denen Dinge, die ich achten, wenn ich diese Art der Optimierung durchführen möchten. Mein Ziel ist es, die Ausführung von BF-Code mit den Vorteilen von Haskell zu ermöglichen - Faulheit (Ich mag archieve, dass der Code nur im Speicher nach Bedarf gehalten werden kann) und Leichtigkeit.

War es hilfreich?

Lösung

Das sieht wirklich wie eine vorzeitige Optimierung zu mir. UNPACK ist vor allem dann nützlich, wenn Sie eine sehr große Anzahl von BFInstructions haben herumsitzen. Ich bezweifle, Sie jemals genug Brainf ** k-Code haben, um es lohnt sich. Ich stimme mit Gian, sollte es einfach genug, um zu testen sein, so tun, dass die erste.

In jedem Fall ist die Sache bewusst zu sein, mit UNPACK'ed Werten ist, dass Sie nicht möchten, dass der Compiler zu haben, sie REBOX. Sie sollten mit numerischen ops in Ordnung sein, aber anders als das man sich die Funktionen genau hinschauen müßte Sie verwenden, um zu sehen, wenn Sie jemals die entpackten Werte als nicht-strenges Argument verwenden. Der einzige Weg, um sicher zu sein ist der Kern zu suchen, oder die Schnittstellendateien, um zu sehen, welche Parameter sind streng und welche nicht. Wie immer sicher sein, mit mindestens „-O“ zu kompilieren.

Andere Tipps

Ist das wirklich notwendig? Stoßen Sie Performance-Probleme mit diesem Code, dass Sie denken, das Ergebnis der boxed Werte sind? Wenn nicht, nicht stören.

Wenn Sie glauben, dass dies der Fall ist, dann diese Seite im GHC Handbuch scheint die notwendigen Beschränkungen in einem übersichtlichen Liste Format zur Verfügung zu stellen.

Die wichtigsten Punkte zu sein scheinen, dass jede Art von Interaktion zwischen polymorphen Funktionen oder Namen und unboxed Typen, die nicht durch den Compiler abgelehnt wird noch bösen Raum Lecks führen könnte. Auch ohne es zu versuchen, vermute ich, dass Sie nicht Ausnahmen im Fall eines Überlaufes geworfen bekommen, zum Beispiel, so vermutlich sollten Sie diese Art der Sache selbst erkennen. Ein einfacher Test überprüfen könnte, wenn dies tatsächlich der Fall ist oder nicht.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top