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


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




[6]

traceFamily s l = foldM getParent s l

where getParent s f = f s

-используя traceFamily, можно легко составлять сложные запросы mothersPaternalGrandfather s= traceFamily s [mother, father, father] paternalGrandmother s= traceFamily s [father, mother]

Функция traceFamily использует foldM для создания простого способа просмотра родового дерева на любую глубину и в любом направлении. Фактически, проще написать traceFamily s [father, mother], чем использовать функцию paternalGrandmother!

Использование функции foldM в блоке do более характерно:

Код содержится в файле example4.hs

-Dict - просто конечное отображение из строк в строки type Dict = FiniteMap String String

вспомогательная функция, используемая с foldl addEntry:: Dict -> Entry -> Dict

addEntry d e = addToFM d (key e) (value e)

-- вспомогательная функция, используемая с foldM внутри монады IO addDataFromFile:: Dict -> Handle -> IO Dict

addDataFromFile dict hdl = do contents <- hGetContents hdl

entries <- return (map read (lines contents)) return (foldl (addEntry) dict entries)

эта программа формирует словарь из записей файлов, названных в командной строке, и затем печатает его в виде ассоциированного

-- списка

main :: IO ()

main = dofiles <- getArgs

handles <- mapM openForReading files dict <- foldM addDataFromFile emptyFM handles print (fmToList dict)

Функция filterM работает внутри монады как списковая функция filter. Она берёт предикатную функцию, которая возвращает в монаду значение типа Boolean, и список значений. Функция filterM возвращает в монаду список тех значений, для которых значение предиката равно True.

filterM filterM p []

filterM p (x:xs)

Monad m => (a -> m Bool) -> [a] -> m [a]

return []

do b <- p x

ys <- filterM p xs

return (if b then (x:ys) else ys)

ФП 02005-03 01

Лист 24

№ докум.

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


Вот пример того, как функция filterM может быть использована внутри монады IO для выделения из списка директорий:

Код содержится в файле example5.hs

import Monad import Directory import System

- Обратите внимание: doesDirectoryExist имеет тип FilePath -> IO Bool

- эта программа печатает только те директории, которые названы -- в командной строке main :: IO ()

main = donames <- getArgs

dirs <- filterM doesDirectoryExist names mapM putStrLn dirs

Функция zipWithM - это монадическая версия списковой функции zipWith. Функция zipWithM работает аналогично, но не возвращает результат. Она используется в случае, если важны только побочные эффекты монадических вычислений.

zipWithM::

zipWithM f xs ys=

zipWithM ::

zipWithM f xs ys=

(Monad m) => (a -> b -> m c) -> [a] -> [b] -> m [c]

sequence (zipWith f xs ys)

(Monad m) => (a -> b -> m c) -> [a] -> [b] -> m ()

sequence (zipWith f xs ys)

1.5.2.3. Условные монадические вычисления

Существует две функции, обеспечивающие условное выполнение монадических вычислений. Функция when берёт аргумент типа Boolean и монадическое вычисление с модулем типа () и производит вычисление только в том случае, если значение аргумента типа Boolean равно True. Функция unless работает аналогично, но она производит вычисление, пока значение типа Boolean не равно True.

when when p s

unless unless p s

(Monad m) => Bool -> m () -> m () if p then s else return ()

(Monad m) => Bool -> m () -> m () when (not p) s

1.5.2.4. Функция ap и втягивающие функции

Втягивание - это монадическая операция конвертации немонадической функции в эквивалентную функцию, которая оперирует монадическими значениями. Говорят, что функция «втянута в монаду» операторами втягивания. Втянутая функция используется для оперирования монадическими значениями вне блока do, а также для сокращения кода внутри блока do.

ИзМЛист

№ докум.

ФП 02005-03 01


£ то

/iftM - это простейший втягивающий оператор, который втягивает в монаду функцию одного аргумента.

liftM:: (Monad m) => (a -> b) -> (m a -> m b)

liftM f = \a -> do { a <- a; return (f a) }

Втягивающие операторы также определены и для функций с большим количеством аргументов. Например, MftM2 втягивает функции двух аргументов:

liftM2 :: (Monad m) => (a -> b -> c) -> (m a -> m b -> m c)

liftM2 f = \a b -> do { a <- a; b <- b; return (f a b) }

Аналогично определяются функции большего количества аргументов. Функции до tiftM5 определены в модуле Monad.

Для того чтобы увидеть, каким образом втягивающие операторы сокращают код, рассмотрим вычисление в монаде типа Maybe с использованием функции swapNames :: String -> String. Можно сделать так:

getName:: String -> Maybe String

getName name = do

let db = [("John", "Smith, John"), ("Mike", "Caine, Michael")]

tempName <- lookup name db

return (swapNames tempName)

Но с помощью функции /i/tM мы можем использовать /i/tM swapNames как функцию типа Maybe String -> Maybe String:

Код содержится в файле example6.hs

getName:: String -> Maybe String

getName name = do

let db = [("John", "Smith, John"), ("Mike", "Caine, Michael")]

liftM swapNames (lookup name db)

Разница ещё более заметна при использовании втягивающих функций с большим количеством аргументов.

Втягивающие функции позволяют создание очень компактных конструкций с использованием функций более высоких порядков. Для понимания следующего примера вам, возможно, потребуется ознакомиться с монадическими функциями для монады списка (в частности >>=). Представьте, как вы смогли бы реализовать данную функцию без втягивания оператора:

Код содержится в файле example7.hs

- allCombinations возвращает список, содержащий результат -- применения бинарного оператора ко всем комбинациям -- элементов данных списков

-- Например, результатом allCombinations (+) [[0, 1], [1, 2, 3]] будет -- [0 + 1, 0 + 2, 0 + 3, 1 + 1, 1 + 2, 1 + 3], или [1, 2, 3, 2, 3, 4]

ФП 02005-03 01

Лист 26

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



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