Я новичок в Haskell, и я столкнулся с ситуацией, когда хотел бы использовать государственную монаду. (Или, по крайней мере, я думаю, что это то, что я хотел бы использовать.) Для государственной монады существует миллион учебных пособий, но все они, похоже, полагают, что моя главная цель - понять ее на глубоком концептуальном уровне и следовательно, они останавливаются перед частью, где они говорят, как на самом деле разрабатывать программное обеспечение с ней. Поэтому я ищу помощь с упрощенным практическим примером.Как я могу написать этот простой код, используя государственную монаду?
Ниже представлена очень простая версия того, как выглядит мой текущий код. Как вы можете видеть, я пронизываю состояние через свои функции, и мой вопрос - просто переписать код с помощью нотации do
, чтобы мне не пришлось это делать.
data Machine = Register Int
addToState :: Machine -> Int -> Machine
addToState (Register s) a = Register $ s+a
subtractFromState :: Machine -> Int -> Machine
subtractFromState (Register s) a = Register (s-a)
getValue :: Machine -> Int
getValue (Register s) = s
initialState = Register 0
runProgram = getValue (subtractFromState (addToState initialState 6) 4)
Код моделирует простую абстрактную машину, которая имеет один регистр, а также инструкции для добавления в реестр, вычесть из него, и получить его значение. «Программа» в конце инициализирует регистр до 0, добавляет к нему 6, вычитает 4 и возвращает результат, который, конечно, равен 2.
Я понимаю цель государственной монады (или, по крайней мере, думаю, что я делаю), и я надеюсь, что это позволит мне переписать это так, что я в конечном итоге с чем-то вроде
runProgram :: ???????
runProgram = do
put 0
addToState 6
subtractFromState 4
value <- getValue
return value
Однако, несмотря на все учебники, которые я читал, я до сих пор не знаю, как превратить мой код в эту форму.
Конечно, состояние моего фактического компьютера намного сложнее, и я также передаю его вывод (который будет передан другой машине) и другие вещи, поэтому я очень хочу его упростить. Знание того, как это сделать для этого упрощенного примера, будет очень полезной.
Обновление: после отличного ответа Ли. Теперь я знаю, как это сделать, но я зациклился на том, как писать код в той же элегантной форме, когда у меня есть несколько взаимодействующих машин. Я спросил об этом в a new question.
Большое вам спасибо, это неоценимо. Мне пришлось внести ряд изменений, чтобы заставить его работать (о чем я вообще не жалуюсь, было очень поучительно это сделать). Я не уверен, отредактировать их в своем ответе или оставить его как есть - дайте мне знать, если у вас есть предпочтения. – Nathaniel
@Nathaniel - Вы можете внести необходимые изменения. – Lee
Если вы заинтересованы в дальнейшем, у меня есть [следовать по вопросу] (http://stackoverflow.com/questions/39813675/simulating-interacting-stateful-objects-in-haskell) о том, как программировать в этом стиле, когда У меня есть несколько взаимодействующих объектов с сохранением состояния. – Nathaniel