Этот ответ Я написал несколько дней назад, может быть полезным.Короче говоря, State s
- это просто удобный способ имитации "функций с состоянием" f :: a -> b
как чистых функций f :: (a,s) -> (b,s)
.Чтобы соответствовать структуре монады, хотя они карри, так (примерно) в форме f :: a -> s -> (b,s)
.
Тип State s b
примерно равен s -> (b,s)
, что может быть прочитано как «вычисление, которое возвращает значение b
и конечное состояние s
и которое требует, чтобы начальное состояние s
былобежать".Поэтому монадическая функция a -> State s b
- это функция, которая принимает входные данные a
и может запускаться при заданном начальном состоянии s
для получения значения b
и конечного состояния s
.
Ваша функция isOdd
,
isOdd x :: Int -> State Parity Int
isOdd x = state $ \p -> (if p == Odd then x + 5 else x - 6, not' p)
, что примерно,
isOdd' x :: Int -> Parity -> (Int,Parity)
isOdd' x p = (if p == Odd then x + 5 else x - 6, not' p)
А ваш звонок,
apply n = runState (isOdd n) Even
, примерно,
apply' n = isOdd' x Even
Вот и все.По сути, вы вычисляете
apply' n = --definition of apply'
isOdd' n Even
-- definition of isOdd'
(\x p -> (if p == Odd then x + 5 else x - 6, not' p)) n Even
-- application to the arguments `n` and `Even`
= (if Even == Odd then n + 5 else n - 6, not' Even)
-- simplifying
= (n - 6, Odd)
,
apply' n = (n - 6, Odd)
Вот пример того, как правильно упорядочить вашу функцию,
f :: Int -> State Parity Int
f n = isOdd n >>= (\x -> isOdd x)
или эквивалентно
f :: Int -> State Parity Int
f n = do x <- isOdd n
isOdd x
Когда вы запускаете его, например, через apply n = runState (f n) Even
, вы сначала запускаете isOdd n Even
, чтобы получить результат m
и новое конечное состояние, которое будет False
, а затем - isOdd m False
.