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

标签 optimization haskell ghc unboxing brainfuck

我正在尝试编写一个解析和执行 Brainfuck 代码的小脚本,以了解 GHC 优化选项,我正在尝试优化代码以便更快一些并了解那里发生了什么。

其中一部分是 BF 代码的内部表示,我为此使用了一种特殊的数据类型。这是源代码,包括进行转换的两个函数:

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 []                                   = []

这个想法是,代码将从一些输入(字符串)中读取,由上述代码进行预解析和简化,然后由其他一些函数执行。 (假设输入是有效的)。

为了优化此示例,我尝试将 MovePointer 的 Int 参数拆箱。和 AdjustValue通过执行以下操作来构造构造函数:
data BFinstruction -- BangPatterns
  = AdjustValue {-# UNPACK #-} !Int
  | MovePointer {-# UNPACK #-} !Int
  | GetChar
  | PutChar
  | Loop BFcode
  deriving (Eq)

这将使盒装的 Int输入未装箱的原始 Int# type,它是 GHc 的一个实现细节。在我阅读的过程中,这个选项只在少数情况下有用,所以我想问一下,如果我想进行这种优化,我需要注意哪些事项。我的目标是允许使用 Haskell 的好处执行 BF 代码 - 懒惰(我想归档,代码可能只根据需要保存在内存中)和简单性。

最佳答案

这真的有必要吗?您是否遇到了您认为是装箱值结果的代码的性能问题?如果没有,请不要打扰。

如果您确实相信是这种情况,那么 this page in the GHC manual似乎以方便的列表格式提供了必要的限制。

要点似乎是多态函数或名称与未被编译器拒绝的未装箱类型之间的任何交互仍可能导致严重的空间泄漏。另外,如果不尝试,我怀疑您不会在溢出的情况下抛出异常,例如,所以大概您应该自己检测到这种事情。一个简单的测试可以验证是否确实如此。

关于optimization - 如果我在 Haskell/GHC 中使用未装箱类型(如 Int#),我应该注意哪些事项?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3641573/

相关文章:

haskell - 如何在 eeePc 701/Ubuntu Netbook Remix 1.6 (Lucid) 上构建 cabal-install

optimization - 一般来说,调用外部程序的成本有多高?

c - 如何编写符合 ISO-C 的代码同时允许在排序点之间执行多条指令?

haskell - 让 Cabal 使用 GHC 6.12.1

haskell - 如何捕获并忽略 Haskell 中的错误调用

haskell - 是否可以使用 Free 在 DSL 中实现多态函数

haskell - 启用 TypeFamilies 使代码不再构建

php - 生成具有不规则步长的范围。优化

python - scipy.optimize.leastsq : not a proper array of floats

haskell - 如何正确地将 IO 添加到 attoparsec Parser?