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

-- Использование compare может оказаться более

-- эффективным для сложных типов.

compare x y

| x == y

=

EQ

| x <= y

=

LT

| otherwise =

GT

x <= y

=

compare x y /= GT

x <

y

=

compare x y == LT

x >= y

=

compare x y /= LT

x >

y

=

compare x y == GT

max x y

| x <= y

=

y

| otherwise =

x

min x y

| x <= y

=

x

| otherwise =

y

Все функции определены в декларативном стиле. Тип Ordering кодирует результат операции сравнения.

Два числа могут быть либо равны (значение EQ), либо первое меньше второго (значение LT), либо первое

больше второго (значение GT).

Обратите внимание на функцию compare. Мы не пишем дословное определение значений типа Ordering:

compare x y

| x == y

=

EQ

| x <

y

=

LT

| x >

y

=

GT

Какой стиль лучше? | 67

В этом случае функция compare была бы определена через две других функции класса Ord, а именно

больше > и меньше < . Мы же хотим минимизировать число функций в этом определении. Поэтому вместо

этого определения мы полагаемся на очерёдность обхода альтернатив в охранном выражении.

Если первый случай не прошёл, то во втором случае нет разницы между функциями < и <=. А если не

прошёл и этот случай, то остаётся только вернуть значение GT. Так мы определили функцию compare через

одну функцию класса Ord.

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

для списков, одна из них возможно вам уже порядком поднадоела:

-- Преобразование списка

map :: (a -> b) -> [a] -> [b]

map f []

= []

map f (x:xs) = f x : map f xs

-- Фильтрация списка

filter :: (a -> Bool) -> [a] -> [a]

filter p []

= []

filter p (x:xs) | p x

= x : filter p xs

| otherwise = filter p xs

-- Свёртка списка

foldr

:: (a -> b -> b) -> b -> [a] -> b

foldr f z []

=

z

foldr f z (x:xs) =

f x (foldr f z xs)

Приведём несколько примеров для функции foldr:

and, or :: [Bool] -> Bool

and = foldr (&& ) True

or

= foldr (||) False

(++) :: [a] -> [a] -> [a]

[]

++ ys = ys

(x:xs) ++ ys = x : (xs ++ ys)

concat :: [[a]] -> [a]

concat = foldr (++) []

Функции and и or выполняют логические операции на списках. Так каждый конструктор (:) заменяется

на соответствующую логическую операцию, а пустой список заменяется на значение, которое не влияет на

результат выполнения данной логической операции. Имеется ввиду, что функции (&& True) и (|| False)

дают тот же результат, что и функция id x = x. Функция (++) объединяет два списка, а функция concat

выполняет ту же операцию, но на списке списков.

Функция zip принимает два списка и смешивает их в список пар. Как только один из списков оборвётся

оборвётся и список-результат. Эта функция является частным случаем более общей функции zipWith, кото-

рая принимает функцию двух аргументов и два списка и составляет новый список попарных применений.

-- zip-ы

zip :: [a] -> [b] -> [(a, b)]

zip = zipWith (,)

zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]

zipWith z (a:as) (b:bs) =

z a b : zipWith z as bs

zipWith _ _ _

=

[]

Посмотрим как работают эти функции в интерпретаторе:

Prelude> zip [1,2,3] ”hello”

[(1,’h’),(2,’e’),(3,’l’)]

Prelude> zipWith (+) [1,2,3] [3,2,1]

[4,4,4]

Prelude> zipWith (*) [1,2,3] [5,4,3,2,1]

[5,8,9]

Отметим, что в Prelude также определена обратная функция unzip:

68 | Глава 4: Декларативный и композиционный стиль

unzip

:: [(a,b)] -> ([a], [b])

Она берёт список пар и разбивает его на два списка.

Пока по этим определениям кажется, что композиционный стиль совсем нигде не применяется. Он встре-

тился нам лишь в функции break. Но давайте посмотрим и на функции с композиционным стилем:

lines

:: String -> [String]

lines ””

=

[]

lines s

=

let (l, s’) = break (== ’\n’) s

in

l : case s’ of

[]

-> []

(_:s’’) -> lines s’’

Функция line разбивает строку на список строк. Эти строки были разделены в исходной строке символом

переноса ’\n’.

Функция break принимает предикат и список и возвращает два списка. В первом все элементы от начала

списка, которые не удовлетворяют предикату, а во втором все остальные. Наш предикат (== ’\n’) выделяет

все символы кроме переноса каретки. В строке

let (l, s’) = break (== ’\n’) s

Мы сохраняем все символы до ’\n’ от начала строки в переменной l. Затем мы рекурсивно вызываем

функцию lines на оставшейся части списка:

in

l : case s’ of

[]

-> []

(_:s’’) -> lines s’’

При этом мы пропускаем в s’ первый элемент, поскольку он содержит символ переноса каретки.

Посмотрим на ещё одну функцию для работы со строками.

words

:: String -> [String]

words s

=

case dropWhile Char. isSpace s of

”” -> []

s’ -> w : words s’’

where (w, s’’) = break Char. isSpace s’

Функция words делает тоже самое, что и lines, только теперь в качестве разделителя выступает пробел.

Функция dropWhile отбрасывает от начала списка все элементы, которые удовлетворяют предикату. В строке

case dropWhile Char. isSpace s of

Мы одновременно отбрасываем все первые пробелы и готовим значение для декомпозиции. Дальше мы

рассматриваем два возможных случая для строк.

”” -> []

s’ -> w : words s’’

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

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

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

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

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

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

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

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

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