J'essaye d'écrire un petit script qui analyse et exécute du code Brainfuck, pour comprendre les options d'optimisation de GHC, j'essaie d'optimiser le code pour être un peu plus rapide et comprendre ce qui se passe là-bas.De quoi devrais-je faire attention si j'utilise un type non boxé (comme Int #) dans Haskell/GHC?
Sur les parties est la représentation interne du code BF, j'utilise un type de données spécial pour cela. Voici le code source, inclus les deux fonctions qui font les 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 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 [] = []
L'idée est que le code sera lu à partir une entrée (chaîne), preparsed et simplifiée par le code ci-dessus, puis exécuté par certains autres fonctions. (On suppose que l'entrée est valide).
Afin d'optimiser cet exemple, j'ai essayé de unbox Int params des constructeurs MovePointer
et AdjustValue
en faisant domething comme ceci:
data BFinstruction -- BangPatterns
= AdjustValue {-# UNPACK #-} !Int
| MovePointer {-# UNPACK #-} !Int
| GetChar
| PutChar
| Loop BFcode
deriving (Eq)
Cela transforme le type Int
en boîte dans une boîte ouverte, Int#
brut type, qui est un détail d'implémentation de GHc. Comme je l'ai lu, cette option n'est bonne que dans quelques cas, je veux donc demander, de quelles choses je dois faire attention si je veux effectuer ce genre d'optimisation. Mon but est de permettre l'exécution du code BF en utilisant les avantages de Haskell - la paresse (je veux archiver, que le code ne peut être conservé que si nécessaire en mémoire) et la facilité.
Je me demandais juste combien de personnes vont étiqueter cette offensive, même si BrainF ** k est une langue réelle ... – Oded