Nik*_*nni 11 haskell emulation
我正在编写我的第一个真正的Haskell项目,而且我在程序中组织状态时遇到了麻烦.它是一个Gameboy Color模拟器,因此有很多小标志,整个状态看起来像
data Memory s = Memory { memory :: STUArray s Word16 Word8
, registers :: STUArray s Word8 Word8
, sp :: STRef s Word16
, pc :: STRef s Word16
, cycles :: STRef s Word16
, ime :: STRef s Bool --Interrupt Master Enable Flag
, halt :: STRef s Bool --Are we halted or not
, mode :: STRef s GPUMode -- GPU mode
, line :: STRef s Word8 -- GPU line
, transferred :: STRef s Bool
, gpuCycles :: STRef s Word16
, window :: Window
, renderer :: Renderer
}
Run Code Online (Sandbox Code Playgroud)
我做的所有读/写状态如下:
data Address = OneRegister Register
| TwoRegister {registerA :: Register, registerB :: Register}
| MemAddr Word16
| SP
| PC
| CYCLES
| IME
| HALT_STATE
| GPU_MODE
| GPU_LINE
| GPU_TRANSFERRED_LINE
| GPU_CYCLES
data MemVal = MemVal8 Word8
| MemVal16 Word16
| Flag Bool
| Mode GPUMode
read :: Memory s -> Address -> ST s MemVal
write :: Memory s -> Address -> MemVal -> ST s ()
Run Code Online (Sandbox Code Playgroud)
你可以看到:https://github.com/nikhilunni/HaskellBoy/blob/master/src/Memory.hs
有没有更干净的方式来组织一切?如果可能的话,我想分解各种组件(CPU,GPU,盒式磁带组切换等)之间的状态.在Haskell中拥有一个庞大的单片状态是不是惯用的?
将新状态添加到程序中是一件非常痛苦的事情.Control.Lens包似乎是正确的小巷,但我不确定我是否可以很容易地将它与ST结合起来.
谢谢!
镜片对于这种东西来说绝对是一个很好的帮助,但你宁愿在monad中使用一个大的,嵌套的纯状态对象State,而不是ST.而且我认为对于所有这些变量可能都没问题,尽管它可能不适用于数组(需要对每次修改进行深度复制).
所以我可以想到两个选择:
STRefs完全抛弃这些,支持基于镜头的更新State.ST,但是为了在快速的现代计算机上模拟Game Boy,它可能会起作用.拆分内存类型以便可以保留数组ST,但将所有其他状态组合在STRef一个纯数据结构中.然后,你可以使用镜头.
data Memory s = Memory { memory :: STUArray s Word16 Word8
, registers :: STUArray s Word8 Word8
, memRefs :: STRef s MemRefs
, window :: Window
, renderer :: Renderer
}
data MemRefs = MemRefs { _sp :: Word16
, _pc :: Word16
, _cycles :: Word16
, _ime :: Bool --Interrupt Master Enable Flag
, _halt :: Bool --Are we halted or not
, _mode :: GPUMode -- GPU mode
, _line :: Word8 -- GPU line
, _transferred :: Bool
, _gpuCycles :: Word16
}
mkLenses ''MemRefs
Run Code Online (Sandbox Code Playgroud)好处是,您现在可以将MemRef类型组合在一起,并使用镜头方便地向下伸入结构中.通过使结构更像树,更新实际上将变得更有效.(你可能也想拆除那些Word16和那些Bool字段,把这些小类型盒装起来真的很浪费.)
即便如此,您应该做好准备,这将不会像C++中的类似复杂的实现一样快.为了获得相当的性能,你可能不得不手工处理所有状态以使用所有状态信息编码的单一 STArray状态,并编写丑陋的OO风格的getter和setter ST以使其远程方便.
| 归档时间: |
|
| 查看次数: |
370 次 |
| 最近记录: |