Если класс Monad
эквивалентен Kleisli, то в нём должны выполнятся точно такие же свойства. Запишитесвойства класса Kleisli
через методы класса Monad104 | Глава 6: Функторы и монады: теория
Глава 7
Функторы и монады: примеры
В этой главе мы закрепим на примерах то, что мы узнали о монадах и функторах. Напомню, что с по-
мощью монад и функторов мы можем комбинировать специальные функции вида (a ->
m b) с другимиспециальными функциями.
У нас есть функции тождества и применения:
class Functor
f wherefmap ::
(a -> b) -> f a -> f bclass Functor
f => Applicative f wherepure
::
a -> f a(<*>
)::
f (a -> b) -> f a -> f bclass Monad
m wherereturn
::
a -> m a(>>=
)::
m a -> (a -> m b) -> m b(=<<
) :: (a -> m b) -> m a -> m b(=<<
) = flip (>>=)Вспомним основные производные функции для этих классов:
Или в терминах класса Kleisli
:-- Композиция
(>=>
) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)(<=<
) :: Monad m => (b -> m c) -> (a -> m b) -> (a -> m c)-- Константные функции
(*>
) :: Applicative f => f a -> f b -> f b(<*
) :: Applicative f => f a -> f b -> f a-- Применение обычных функций к специальным значениям
(<$>
):: Functor
f => (a -> b) -> f a -> f bliftA
:: Applicative
f => (a -> b)->
f a -> f bliftA2 :: Applicative
f => (a -> b -> c)->
f a -> f b -> f cliftA3 :: Applicative
f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d-- Преобразование элементов списка специальной функцией
mapM
:: Monad
m => (a -> m b) -> [a] -> m [b]Нам понадобится модуль с определениями типов и экземпляров монад для всех типов, которые мы рас-
смотрели в предыдущей главе. Экземпляры для []
и Maybe уже определены в Prelude, а типы State, Readerи Writer
можно найти в библиотеках mtl и transformers. Пока мы не знаем как устанавливать библиотекиопределим эти типы и экземпляры для Monad
самостоятельно. Возможно вы уже определили их, выполняяодно из упражнений предыдущей главы, если это так сейчас вы можете сверить ответы. Определим модуль
Types
:module Types
(State
(.. ), Reader(.. ), Writer(.. ),runState, runWriter, runReader,
| 105
module Control.Applicative
,module Control.Monad
,module Data.Monoid
)where
import Data.Monoid
import Control.Applicative
import Control.Monad
-------------------------------------------------
-- Функции с состоянием
--
--
a -> State s b
data State
s a = State (s -> (a, s))runState :: State
s a -> s -> (a, s)runState (State
f) = finstance Monad
(State s) wherereturn a
= State $
\s -> (a, s)ma >>=
mf = State $ \s0 ->let
(b, s1) = runState ma s0in
runState (mf b) s1
---------------------------------------------------
-- Функции с окружением
--
--
a -> Reader env b
data Reader
env a = Reader (env -> a)runReader :: Reader
env a -> env -> arunReader (Reader
f) = finstance Monad
(Reader env) wherereturn a
= Reader $
const ama >>=
mf= Reader $
\env ->let
b = runReader ma envin
runReader (mf b) env
---------------------------------------------------
-- Функции-накопители
--
--
Monoid msg => a -> Writer msg b
data Writer
msg a = Writer (a, msg)deriving
(Show)runWriter :: Writer
msg a -> (a, msg)runWriter (Writer
f) = finstance Monoid
msg => Monad (Writer msg) wherereturn a
= Writer
(a, mempty)ma >>=
mf= Writer
(c, msgA ‘mappend‘ msgF)where
(b, msgA) = runWriter ma(c, msgF) =
runWriter $ mf bЯ пропустил определения для экземпляров классов Functor
и Applicative, их можно получить из экзем-пляра для класса Monad
с помощью стандартных функций liftM, return и ap из модуля Control.Monad.Нам встретилась новая запись в экспорте модуля. Для удобства мы экспортируем модули
Control.Applicative
, Control.Monad и Data.Monoid целиком. Для этого мы написали ключевое словоmodule
перед экспортируемым модулем. Теперь если мы в каком-нибудь другом модуле импортируеммодуль Types
нам станут доступными все функции из этих модулей.Мы определили экземпляры для Functor
и Applicative с помощью производных функций класса Monad.106 | Глава 7: Функторы и монады: примеры
7.1 Случайные числа
С помощью монады State
можно имитировать случайные числа. Мы будем генерировать случайные числаиз интервала от 0 до 1 с помощью алгоритма:
nextRandom :: Double -> Double
nextRandom =
snd . properFraction . (105.947 * )Функция properFraction возвращает пару, которая состоит из целой части и остатка числа. Взяв второй