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

零件的内部代表是BF代码,我为此使用了特殊的数据类型。这是Sourcecode,包括进行转换的两个功能:

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

这个想法是,将从某些输入(字符串)读取代码,由上述代码进行预处理和简化,然后由其他功能执行。 (假定输入是有效的)。

为了优化此示例,我尝试拆开该示例的int参数 MovePointerAdjustValue 这样做的构造函数这样:

data BFinstruction -- BangPatterns
  = AdjustValue {-# UNPACK #-} !Int
  | MovePointer {-# UNPACK #-} !Int
  | GetChar
  | PutChar
  | Loop BFcode
  deriving (Eq)

这会转盒 Int 输入未盒的未包装 Int# 类型,这是GHC的实现细节。正如我阅读的那样,此选项仅在少数情况下是好的,所以我想问一下,如果我想执行这种优化,我必须注意哪些事情。我的目标是允许使用Haskell -Laziness的好处执行BF代码(我想拱起,只能根据需要保留代码)和轻松度。

有帮助吗?

解决方案

对我来说,这确实看起来像是过早的优化。当您有很多数量时,打开包装大多是有用的 BFInstructionS坐在周围。我怀疑您将有足够的脑力** k代码以使其值得。我同意吉安(Gian)的观点,它应该足够简单,可以进行测试,因此首先要进行测试。

无论如何,要注意打开包装值的事情是,您不希望编译器重新包装它们。您应该对数值操作不满意,但是除此之外,您还必须仔细查看所使用的功能,以查看是否曾经将未包装的值用作非图案参数。确定的唯一方法是查看核心或接口文件,以查看哪些参数严格而不是什么参数。与往常一样,请确保至少使用“ -o”编译。

其他提示

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

如果您确实相信这种情况,那就 此页面在GHC手册中 似乎以方便的列表格式提供必要的限制。

主要要点似乎是,编译器未拒绝的多态函数或名称和未框类型之间的任何类型的相互作用仍然可能导致讨厌的空间泄漏。另外,如果不尝试它,我怀疑您不会在溢出的情况下会出现例外,所以大概您应该自己发现这种事情。一个简单的测试可以验证是否确实是这种情况。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top