Ich versuche, ein kleines Skript zu schreiben, das Brainfuck-Code analysiert und ausführt, um die GHC-Optionen der Optimierung zu verstehen, ich versuche, den Code zu optimieren, um ein bisschen schneller zu sein und zu verstehen, was dort vor sich geht.Von welchen Dingen sollte ich vorsichtig sein, wenn ich in Haskell/GHC ungepackten Typ (wie Int #) verwende?
Einer der Teile ist die interne Repräsentation von BF-Code, ich verwende hierfür einen speziellen Datentyp. Hier ist der Sourcecode, enthalten die beiden Funktionen, 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 ausgeführt andere Funktionen. (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 den boxed Int
Typen in einen unboxed, roh Int#
drehen Typ, der ein Implementierungsdetail von GHc ist. Wie ich gelesen habe, ist diese Option nur in wenigen Fällen gut, also möchte ich fragen, auf welche Dinge ich achten muss, wenn ich diese Art der Optimierung durchführen möchte. Mein Ziel ist es, die Ausführung von BF-Code mit den Vorteilen von Haskell zu ermöglichen - Faulheit (ich möchte erreichen, dass der Code nur im Speicher gehalten werden kann) und Leichtigkeit.
Ich frage mich nur, wie viele Leute diese Offensive markieren, obwohl BrainF ** k eine aktuelle Sprache ist ... – Oded