I am trying to write a small script that analyzes and executes Brainfuck code in order to understand the GHC optimization options, I am trying to optimize the code to be a little faster and understand what is happening.
Inside the parts there is an internal representation of the BF code, for this I use a special data type. Here, the source code included two functions that perform conversions:
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 cs 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 [] = []
The idea is that the code will be read from some input (line), prepared and simplified by the above code, and then executed by some other functions. (It is assumed that the entry is valid).
To optimize this example, I tried to unpack the Int parameters of the MovePointer and AdjustValue by doing the following:
data BFinstruction -- BangPatterns = AdjustValue {-
This will turn the box type Int into unboxed, raw Int# , which is a detail of the GHc implementation. As I read, this option is only good in a few cases, so I want to ask what things I should pay attention to if I want to perform such an optimization. My goal is to allow the execution of BF code, taking advantage of Haskell-laziness (I want to archive that code can only be stored as needed in memory) and simplicity.
optimization haskell ghc brainfuck
fuz
source share