gpt4 book ai didi

haskell - Haskell 中不同的、交互的状态级别

转载 作者:行者123 更新时间:2023-12-02 21:26:40 25 4
gpt4 key购买 nike

我正在模拟 4 位微处理器。我需要跟踪寄存器、内存和运行输出(还有一个获取执行周期计数器的奖励点)。我已经成功地在没有 monad 的情况下做到了这一点,但同时明确地传递这么多东西感觉很困惑。而且函数定义又乱又长,难以阅读。

我尝试用 monad 来做到这一点,但它只是不适合在一起。我尝试将所有单独的状态组件视为单一类型,但这给我留下了如何生成值的问题。

State Program () -- Represents the state of the processor after a single iteration of the fetch execute cycle

是唯一有意义的类型。但那时为什么还要麻烦呢?我尝试通过将字符串从复合类型中拉出并将其视为值来分解它

State Program' String

效果很好,除了我需要 RUNNING 输出这一事实。无论我做什么,我都无法同时保留字符串和状态。

现在我正在尝试解决 monad 转换器。看来我必须将所有不同级别的状态分开。但我的头快爆炸了。

StateT Registers (StateT Memory (State Output)) a = 
StateT (registers -> (StateT Memory (State Output)) (a,registers))

StateT Registers (StateT Memory (State Output)) a =
StateT (registers -> (Memory -> (Output -> (((a,Registers),Memory),Output))))

我什至还没有放入 FEcycle 计数器!

问题:

  1. 我走的路正确吗?
  2. 既然我现在正在拔出 monad 变压器,是否可以停止将“运行输出”视为状态并将其交给 IO monad?那太棒了,我可以打印它,而不是保留它。
  3. 我应该将状态分成几层?我可以看到两个不同的层,但它们彼此紧密依赖(内存和寄存器都依赖于内存和寄存器的状态)。我应该将它们作为一个状态保留在一起还是将它们分开并堆叠起来?哪种方法会产生最具可读性的代码?

最佳答案

将多个状态单子(monad)分层是一个坏主意:您必须组合一堆lift来获取每个状态,仅通过向下的层数来识别它就是堆栈。哎呀!事实上,除了极少数异常(exception),mtl 库通常被设计为与堆栈中的每种“种类”有一个 monad 转换器一起使用。

相反,我建议使用StateT Program IO ()。状态接口(interface)是相同的,正如您所说,您可以简单地使用 liftIOIO 中进行输出。当然,值类型是 (),但这有什么问题呢?您无法从顶级模拟器返回任何相关值。当然,您可能会将更小的、可重用的组件作为模拟器的一部分,并且这些组件将具有相关的结果类型。 (事实上​​,get 就是这样的组件之一。)顶层没有有意义的返回值并没有什么问题。

为了方便地访问该 State 的各个部分,您需要的是镜片; this Stack Overflow answer是一个很好的介绍。它们使您可以简单轻松地访问和修改状态的独立部分。例如,使用 data-lens实现时,您可以轻松编写诸如 regA += 1 之类的内容来递增 regA,或 stack %= drop 2 来删除 的前两个元素堆栈。

当然,它本质上是将您的代码转变为一组全局变量的命令式突变,但这实际上是一个优势,因为这正是您正在模拟的 CPU 所基于的范例。并且与 data-lens-template包中,您可以从一行记录定义中导出这些镜头。

关于haskell - Haskell 中不同的、交互的状态级别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9093282/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com