Estoy tratando de escribir un pequeño script que analiza y ejecuta el código Brainfuck, para entender las opciones de optimización de GHC, estoy tratando de optimizar el código con el fin de ser un poco más rápido y entender lo que está pasando allí.¿De qué cosas debería tener cuidado si estoy usando unboxed type (como Int #) en Haskell/GHC?
En una de las partes es la represantation interna de BF-código, utilice un tipo de datos especial para esto. Aquí está el código fuente, incluidas las dos funciones que están haciendo las conversiones:
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 [] = []
La idea es que el código se puede leer en alguna entrada (cadena), preparsed y simplifica el código anterior y luego ejecutado por algunos otras funciones. (Se supone que la entrada es válida).
el fin de optimizar este ejemplo, he tratado de desempacar el Int params de los MovePointer
y AdjustValue
constructores haciendo domething así:
data BFinstruction -- BangPatterns
= AdjustValue {-# UNPACK #-} !Int
| MovePointer {-# UNPACK #-} !Int
| GetChar
| PutChar
| Loop BFcode
deriving (Eq)
Esto a su vez la caja Int
tipo en un sin embalaje, crudo Int#
tipo, que es un detalle de implementación de GHc. A medida que leo, esta opción solo es buena en algunos casos, por lo que quiero preguntar de qué cosas tengo que prestar atención si deseo realizar este tipo de optimización. Mi objetivo es permitir la ejecución del código BF utilizando los beneficios de Haskell: la pereza (deseo archivar, que el código solo se puede guardar según lo necesitado en la memoria) y la facilidad.
Sólo me preguntaba cuántas personas van a etiquetar esta ofensiva, a pesar de que brainf ** k es un lenguaje real ... – Oded