如果我在Haskell/GHC中使用未装箱的类型(如Int#),我应该注意哪些事项?

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和由上述代码简化,然后通过一些其他功能执行.(假设输入有效).

为了优化这个例子,我尝试通过执行如下操作来取消装配MovePointerAdjustValue构造函数的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,即根据需要在内存中的代码可被保留)和容易.

Joh*_*n L 2

在我看来,这确实是一个过早的优化。当您有大量BFInstructions 时,UNPACK 最有用。我怀疑你是否有足够的大脑代码来使其值得。我同意 Gian 的观点,测试应该足够简单,所以先这样做。

无论如何,对于 UNPACK 值,需要注意的是您不希望编译器必须重新装箱它们。您应该可以接受数字操作,但除此之外,您必须仔细查看您正在使用的函数,看看您是否曾经使用解压缩的值作为非严格参数。唯一确定的方法是查看核心或接口文件,看看哪些参数是严格的,哪些不是。与往常一样,请确保至少使用“-O”进行编译。