Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import Control.Monad(replicateM)
- --Наша монада состояния
- --Представляет собой функцияю из одного состояния в другое
- --st -> (a, st) : здесь st - состояние, a - тип значения которым оперирует монада
- --Функция принимает состояние st и возвращает пару (значение, состояние)
- --ТИП st меняться не будет, это только тип-параметр нашего состояния, к монадам отношения не имеет
- --ТИП а - будет постоянно меняться, один тип-параметр у монады должен быть по определению.
- --State Int a, IO a, [a], Maybe a
- data State st a = State (st -> (a, st))
- --Итак - определение State st как монады.
- instance Monad (State st) where
- --Оператор последовательного соединения (>>) (pipeline)
- --ЯВНО ОПРЕДЕЛЯТЬ ЕГО НЕ ОБЯЗАТЕЛЬНО. ОН МОЖЕТ БЫТЬ ВЫВЕДЕН ИЗ ОПЕРАТОРА (>>=) но мы определим в учебных целях =)
- --Тип :: Monad m => m a -> m b -> m b -- принимает две монады и возвращает "результат слияния"
- -- значение у новой монады берётся из второй
- --Возвращает новую монаду State st, функция которой определена как st = f2 (snd (f1 st)))
- --Функция принимает состояние st и возвращает результат f2(функции второй монады)
- -- от второго элементы пары, возвращаемого результатом f1 от состояния(st).
- --короче говоря состояние передаётся функции первой монады, второй элемент
- --полученой пары(новое состояние) передаётся функции второй монады, которая в свою очередь возвращает состояние
- --более краткая запись функции "\st -> f2 (snd (f1 st)))" выглядит так: "f2 . snd . f1"
- State f1 >> State f2 = State (\st -> f2 (snd (f1 st)))
- --Оператор соединения с "монадической" функцией (>>=) (bind)
- --Тип :: Monad m => m a -> (a -> m b) -> m b
- --Допустим у нас есть монада, читающая строку из ввода getLine :: IO String
- --И функция, создающая монаду при помощи строки(монадическая) putStr :: String -> IO ()
- --тогда можно воспользоваться данным оператором: getLine >>= putStr
- --функция новой монады исполняет функцию первой монады (f1), с помощью её результата получает f2
- --и дальше действует аналогично приведённой выше.
- State f1 >>= mF = State (\st -> let (x, st2) = f1 st
- State f2 = mF x
- in f2 st2)
- --Функция return (unit)
- --Тип :: Monad m => a -> m a
- --ничего не делает с состоянием, какое принимает, такое и возвращает.
- --Зато возвращает х как первый элемент пары. Т.е устанавливает значение монады
- return x = State (\st -> (x, st))
- --Итак, наша монада готова, добавим способы для работы с ней
- --запустить: принимает состояние, и передаёт его функции монады State, результат возвращает
- runState :: st -> State st a -> (a, st)
- runState st (State f1) = f1 st
- --Принимает функцию, возвращает монаду модифицирующую состояние
- modify :: (st -> st) -> State st ()
- modify f = State (\st -> ((), f st))
- --Функция для примера работы с монадическим значением. Вычисляет чётное ли состояние(числовое, Int)
- --Результат возвращается как значение монады
- evenSt :: State Int Bool
- evenSt = State (\st -> (even st, st))
- --собственно, работа с числовой монадой состояния.
- main = print $ runState 0 $ do --вывод результата запуска нижепреведённой монады с числовым состоянием 0
- modify (+1) --модифицировать состояние, прибавить 1
- replicateM 100 (modify (+1)) --то же самое, повторённое 100 раз
- evenSt --последняя монада, определяющая монадическое значение.
- --результат деятельности: (False,101)
- --В итоге State создаёт портянку из функций, модифицирующий состояние, которые начнут
- --рекурсивно дёргать друг друга при "запуске монады".
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement