Я эмулирую 4-битный микропроцессор. Мне нужно отслеживать регистры, память и текущий вывод (бонусные баллы за наличие счетчика циклов выборки-выполнения). Мне удалось сделать это без монад, но это кажется грязным, когда я явно пропускаю столько вещей одновременно. Кроме того, определение функции беспорядочное, длинное и трудночитаемое.
Я пытался сделать это с монадами, и это просто не стыкуется. Я попытался рассматривать все отдельные компоненты состояния как один тип, но это оставило меня с проблемой, что делать со значением.
State Program () -- Represents the state of the processor after a single iteration of the fetch execute cycle
Был единственным типом, который имел хоть какой-то смысл. Но в таком случае зачем вообще заморачиваться? Я попытался разбить его, вытащив строку из моего составного типа и обработав ее как значение
State Program' String
который отлично работал, за исключением того факта, что мне нужен был РАБОТАЮЩИЙ вывод. Что бы я ни делал, я не мог одновременно удерживать и строку, и состояние.
Теперь я пытаюсь бороться с трансформерами монад. Кажется, мне нужно выделить все разные уровни состояния. Но моя голова взрывается быстро.
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!
Вопросы:
- Я на правильном пути?
- Раз уж я сейчас вытаскиваю трансформеры монад, можно ли перестать рассматривать «текущий вывод» как состояние и просто подсунуть его монаде IO? Это было бы здорово, вместо того, чтобы держать его, я мог бы просто распечатать его.
- На сколько слоев я должен разделить состояние? Я вижу два отдельных слоя, но они тесно зависят друг от друга (и память, и регистры зависят от состояния как памяти, так и регистров). Должен ли я держать их вместе как единое состояние или разделить их и сложить? Какой подход создаст наиболее читаемый код?