haskell-notes

параметром m определить два экземпляра:

instance Kleisli m => Monad

m where

instance Monad

m => Kelisli m where

Нужно определить экземпляр одного класса с помощью методов другого.

Свойства класса Monad

Если класс Monad эквивалентен Kleisli, то в нём должны выполнятся точно такие же свойства. Запишите

свойства класса Kleisli через методы класса Monad

104 | Глава 6: Функторы и монады: теория

Глава 7

Функторы и монады: примеры

В этой главе мы закрепим на примерах то, что мы узнали о монадах и функторах. Напомню, что с по-

мощью монад и функторов мы можем комбинировать специальные функции вида (a -> m b) с другими

специальными функциями.

У нас есть функции тождества и применения:

class Functor f where

fmap :: (a -> b) -> f a -> f b

class Functor f => Applicative f where

pure

:: a -> f a

( )

:: f (a -> b) -> f a -> f b

class Monad m where

return

:: 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 b

liftA

:: Applicative f => (a -> b)

-> f a -> f b

liftA2 :: Applicative f => (a -> b -> c)

-> f a -> f b -> f c

liftA3 :: 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) = f

instance Monad (State s) where

return a

= State $ s -> (a, s)

ma >>= mf = State $ s0 ->

let (b, s1) = runState ma s0

in

runState (mf b) s1

—————————————————

— Функции с окружением

a -> Reader env b

data Reader env a = Reader (env -> a)

runReader :: Reader env a -> env -> a

runReader (Reader f) = f

instance Monad (Reader env) where

return a

= Reader $ const a

ma >>= mf

= Reader $ env ->

let b = runReader ma env

in

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) = f

instance Monoid msg => Monad (Writer msg) where

return 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 возвращает пару, которая состоит из целой части и остатка числа. Взяв второй

элемент пары с помощью snd, мы выделяем остаток. Функция nextRandom представляет собой генератор

случайных чисел, который принимает значение с предыдущего шага и строит по нему следующее значение.

Построим тип для случайных чисел:

type Random a = State Double a

next :: Random Double

next = State $ s -> (s, nextRandom s)

Теперь определим функцию, которая прибавляет к данному числу случайное число из интервала от 0 до

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162