fuz*_*fuz 6 optimization unboxing haskell ghc brainfuck
我正在尝试编写一个解析和执行Brainfuck代码的小脚本,以了解GHC的优化选项,我正在尝试优化代码以便更快一些并了解正在发生的事情.
在部分是BF代码的内部represantation,我使用一个特殊的数据类型.这是源代码,包括正在进行转换的两个函数:
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 [] = []
Run Code Online (Sandbox Code Playgroud)
我们的想法是,该代码将某些输入(串)被读取,preparsed和由上述代码简化,然后通过一些其他功能执行.(假设输入有效).
为了优化这个例子,我尝试通过执行如下操作来取消装配MovePointer和AdjustValue构造函数的Int参数:
data BFinstruction -- BangPatterns
= AdjustValue {-# UNPACK #-} !Int
| MovePointer {-# UNPACK #-} !Int
| GetChar
| PutChar
| Loop BFcode
deriving (Eq)
Run Code Online (Sandbox Code Playgroud)
这会将盒装Int类型转换为未装箱的原始Int#类型,这是GHc的实现细节.因为我读,此选项仅在少数情况下很好的,所以我想问一下,这事我得注意,如果我要执行这种优化.我的目标是让使用哈斯克尔的好处BF-代码的执行-懒惰(我想archieve,即根据需要在内存中的代码可被保留)和容易.
在我看来,这确实是一个过早的优化。当您有大量BFInstructions 时,UNPACK 最有用。我怀疑你是否有足够的大脑代码来使其值得。我同意 Gian 的观点,测试应该足够简单,所以先这样做。
无论如何,对于 UNPACK 值,需要注意的是您不希望编译器必须重新装箱它们。您应该可以接受数字操作,但除此之外,您必须仔细查看您正在使用的函数,看看您是否曾经使用解压缩的值作为非严格参数。唯一确定的方法是查看核心或接口文件,看看哪些参数是严格的,哪些不是。与往常一样,请确保至少使用“-O”进行编译。