Читаем Учебник по Haskell полностью

В этой записи мы фильтруем список list предикатом p и преобразуем результат функцией f. Например

возведём в квадрат все чётные элементы списка:

Prelude> [x*x | x <- [1 .. 10], even x]

[4,16,36,64,100]

Предикатов может быть несколько, так например мы можем оставить лишь положительные чётные числа:

Prelude> [x | x <- [-10 .. 10], even x, x >= 0]

[0,2,4,6,8,10]

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

пары слов:

Prelude> [ [x,y] | x <- ”Hello”, y <- ”World”]

[”HW”,”Ho”,”Hr”,”Hl”,”Hd”,”eW”,”eo”,”er”,”el”,

”ed”,”lW”,”lo”,”lr”,”ll”,”ld”,”lW”,”lo”,”lr”,

”ll”,”ld”,”oW”,”oo”,”or”,”ol”,”od”]

Сахар для монад, do-нотация

Монады используются столь часто, что для них придумали специальный синтаксис, который облегчает

подстановку специальных значений в функции нескольких переменных. Монады позволяют комбинировать

специальные функции вида

a -> m b

Если бы эти функции выглядели как обычные функции:

a -> b

их можно было свободно комбинировать с другими функциями. А так нам постоянно приходится поль-

зоваться методами класса Monad. Очень часто функции с побочными эффектами имеют вид:

a1 -> a2 -> a3 -> ... -> an -> m b

А теперь представьте, что вам нужно подставить специальное значение третьим аргументом такой функ-

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

специальное окружение do, в котором специальные функции комбинируются так словно они являются обыч-

ными. Для этого используется обратная стрелка. Посмотрим как определяется функция sequence в окруже-

нии do:

sequence :: [m a] -> m [a]

sequence []

= return []

sequence (mx:mxs)

= do

x

<- mx

xs <- sequence mxs

return (x:xs)

Во втором уравнении сначала мы говорим вычислителю словом do о том, что выражения записаны в мире

монады m. Запись с перевёрнутой стрелкой x <- mx означает, что мы далее в do-блоке можем пользоваться

значением x так словно оно имеет тип просто a, но не m a. Смотрите в этом определении мы сначала извле-

каем первый элемент списка, затем извлекаем хвост списка, приведённый к типу m [a], и в самом конце мы

соединяем голову и хвост и в самом конце оборачиваем результат в специальное значение.

Например мы можем построить функцию, которая дважды читает строку со стандартного ввода и затем

возвращает объединение двух строк:

252 | Глава 17: Дополнительные возможности

getLine2 :: IO String

getLine2 = do

a <- getLine

b <- getLine

return (a ++ b)

В do-нотации можно вводить локальные переменные с помощью слова let:

t = do

b <- f a

c <- g b

let x = c + b

y = x + c

return y

Посмотрим как do-нотация переводится в выражение, составленное с помощью методов класса Monad:

do

a <- ma

=>

ma >>= (\a -> exp)

exp

do

exp1

=>

exp1 >> exp2

exp2

do

let x = fx

=>

let x = fx

y = fy

y = fy

exp

in

exp

Переведём с помощью этих правил определение для второго уравнения из функции sequence

sequence (mx:mxs) = do

x

<- mx

mx >>= (\x -> do

xs

<- sequence mxs

=>

xs <- sequence mxs

=>

return (x:xs)

return (x:xs))

=>

mx >>= (\x -> sequence mxs >>= (\xs -> return (x:xs)))

do или Applicative?

С появлением класса Applicative во многих случаях do-нотация теряет свою ценность. Так например

любой do-блок вида:

f mx my = do

x <- mx

y <- my

return (op x y)

Можно записать гораздо короче:

f = liftA2 op

Например напишем функцию, которая объединяет два файла в один:

appendFiles :: FilePath -> FilePath -> FilePath -> IO ()

С помощью do-нотации:

appendFiles file1 file2 resFile = do

a <- readFile file1

b <- readFile file2

writeFile resFile (a ++ b)

А теперь с помощью класса Applicative:

appendFiles file1 file2 resFile = writeFile resFile =<<

liftA2 (++) (readFile file1) (readFile file2)

Пуд сахара | 253

17.2 Расширения

Расширение появляется в ответ на проблему, с которой трудно или невозможно справится в рамках стан-

дарта Haskell. Мы рассмотрим несколько наиболее часто используемых расширений. Расширения подключа-

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

в текущем модуле.

{-# LANGUAGE

ExtentionName1, ExtentionName2, ExtentionName3 #-}

Обратите внимание на символ решётка, обрамляющие комментарии. Слово LANGUAGE говорит компи-

лятору о том, что мы хотим воспользоваться расширениями с именами ExtentionName1, ExtentionName2,

ExtentionName3. Такой комментарий называется прагмой (pragma). Часто компилятор ghc в случае ошибки

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

Он говорит возможно вы имели в виду расширение XXX. Например попробуйте загрузить в интерпретатор

модуль:

module Test where

class Multi a b where

В этом случае мы увидим ошибку:

Prelude> :l Test

[1 of 1] Compiling Test

( Test. hs, interpreted )

Test. hs:3:0:

Too many parameters for class Multi’

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных