Ремонт принтеров, сканнеров, факсов и остальной офисной техники


назад Оглавление вперед




[14]

instance (Monoid w) => MonadWriter(Writer w) where pass (Writer ((a, f), w)) = Writer (a, f w) listen (Writer (a, w)) = Writer ((a, w), w)

tell s= Writer ((), s)

listens listens f m

censor censor f m

(MonadWriter w m) => (w -> w) -> m a -> m (a, w) do (a, w) <- m; return (a, f w)

(MonadWriter w m) => (w -> w) -> m a -> m a pass $ do a <- m; return (a, f)

Класс MonadWriter выделяет множество удобных функций для работы с монадами Writer. Самый простой и наиболее полезный способ - сообщение, которое добавляет одно или более данных к протоколу. Прослушивающая функция переделывает Writer, которая возвращает величину a и создает выход w в Writer, которая создает величину (a, w) и все еще создает выход w. Это допускает вычисление, чтобы «слушать» протокол на выходе, сгенерированный Writer.

Передаваемая функция немного усложнена. Она преобразовывает Writer, которая производит величину (a, j) и выход w в Writer, которая производит величину a и выход j w. Это отчасти громоздко, поэтому нормально использован функциональный цензор помощника. Функция цензора берет функцию и Writer и производит новую Writer, чей выход - тот же, но чей регистрационный вход был модифицирован функцией.

Прослушивающая функция кроме того управляет тем, что регистрационная часть величины модифицируется поставленной функцией.

2.9.4. Пример

В этом примере, мы представляем себе то же простое применение, которое фильтрует пакеты, основываясь на базе правил, сочетающих в себе исходные и предопределённые множества и полезность пакетов. Первичной работой является фильтрование пакетов, но нам должно это нравиться, чтобы создать протокол деятельности.

Код, имеющийся в example17.hs

- это - формат нашего входного протокола

data Entry = Log {count::Int, msg::String} deriving Eq

-- добавляем сообщение к протоколу logMsg:: String -> Writer [Entry] ()

logMsg s= tell [Log 1 s]

-- управление одним пакетом

filterOne:: [Rule] -> Packet -> Writer [Entry] (Maybe Packet)

ФП 02005-03 01

Лист 48

№ докум.

Копиоова Фоомат


++ (show packet))

filterOne rules packet = do

rule <- return (match rules packet) case rule of

Nothing -> do

logMsg ("DROPPING UNMATCHED PACKET: return Nothing (Just r) -> do

when(logIt r) (logMsg ("MATCH: " ++ (show r) ++ " <=> " ++

(show packet)))

case r of

(Rule Accept ) -> return (Just packet) (Rule Reject ) -> return Nothing

Это было довольно просто, но что если мы хотим объединить двойные последовательные регистрационные данные? Ни одна из существующих функций не позволяет нам модифицировать выход с предшествующих этапов вычисления, но мы можем использовать хитрость «задержанная регистрация», чтобы добавлять регистрационный вход только после того, как мы получим новый вход, который не соответствует ни одному до него.

Код, имеющийся в example17.hs

- слияние идентичных данных в конце протокола. Эта функция использует -- [Entry] как тип протокола и тип результата. Когда два идентичных сообщения -- объеденены, результатом является сообщением с увеличенным счётчиком. Когда -- два других сообщения объединены, сначала регистрируется первое сообщение, -- а второе возвращается как результат.

[Entry] -> Writer [Entry] [Entry]

mergeEntries mergeEntries [] x mergeEntries x [] mergeEntries [el]

:: [Entry] ->

= return x = return x [e2] = let

(Log n msg) = el (Log n msg) = e2

if msg == msg

then return [(Log (n+n) msg)] else do

tell [el]

return [e2]

-- Эта с виду сложная функция на самом деле красива и проста.

-- Она отображает функцию над списком величин, чтобы получать список Writer, -- тогда выполняется каждый автор и объединяются результаты. Результат -- функции - автор, чья величина является списком всех величин из авторов -- и чей регистрационный выход является результатом свертки оператора слияния -- в личные регистрационные данные ( использование инициала как начального -- протокола величины).

groupSame:: (Monoid a) => a ->

ФП 02005-03 01

Лист 49

№ докум.

Копипова Формат


(a -> a -> Writer a a) ->

[b] ->

(b -> Writer a c) -> Writer a [c]

groupSame initial merge [] = do tell initial

return []

groupSame initial merge (x:xs) fn= do

(result,output) <- return (runWriter (fn x)) new <- merge initial output rest <- groupSame new merge xs fn return (result:rest)

- эти фильтры - список пакетов, производящих отфильтрованный список пакета и -- протокол деятельности, в котором объединяются последовательные сообщения

filterAll :: [Rule] -> [Packet] -> Writer [Entry] [Packet]

filterAll rules packets= do

tell [Log 1 "STARTING PACKET FILTER"]

out <- groupSame [] mergeEntries packets (filterOne rules)

tell [Log 1 "STOPPING PACKET FILTER"]

return (catMaybes out)

2.10. Монада Continuation

2.10.1. Обзор

Таблица 10. Свойства монады Continuation

Тип вычисления:

Вычисления, которые могут быть остановлены и возобновлены.

Стратегия связывания:

Привязывание функции к унарному значению создаёт новое возобновление, которое использует функцию, как возобновление унарного вычисления.

Полезна для:

Сложные управляющие структуры, обработка ошибок и создание сопрограмм.

Нуль и плюс:

Пример:

Cont r a

2.10.2. Мотивация

Злоупотребление монадой Continuation может привести к созданию кода, который будет невозможно понять и поддержать. Прежде чем использовать монаду Continuation, будьте уверены, что у вас есть твёрдое понимание выносимого возобновления стиля (CPS), и что возобновления представляют собой лучшее решение вашей определённой задачи. Многие алгоритмы, которые требуют возобновлений в других языках, не требуют их в языке Haskell, благодаря ленивой семантике языка Haskell.

ФП 02005-03 01

Лист 50

№ докум.

Копиоова Фоомат



[стр.Начало] [стр.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]