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

дящие по типу функции. В этой маленькой функции кроется невероятная сила. Посмотрим на несколько

примеров:

Prelude Data.Char> :m -Data.Char

Prelude> let xs = [1,2,3,4,5]

Prelude> foldr (:) [] xs

[1,2,3,4,5]

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

нибудь более конструктивное. Например вычислим сумму всех элементов или произведение:

Prelude> foldr (+) 0 xs

15

Prelude> foldr (*) 1 xs

120

Prelude> foldr max (head xs) xs

5

3.6 Краткое содержание

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

на структуре значений. Мы узнали, что константы в Haskell очень похожи на деревья, а запись констант

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

синонима состоит из композиции и декомпозиции значений.

name

декомпозиция

=

композиция

Существует несколько правил для построения композиций:

• Одно для функций в префиксной форме записи:

f :: a -> b,

x :: a

-------------------------------

(f x) :: b

• И два для функций в инфиксной форме записи:

Это левое сечение:

(*) :: a -> (b -> c),

x :: a

---------------------------------

(x *) :: b -> c

И правое сечение:

(*) :: a -> (b -> c),

x :: b

---------------------------------

(* x) :: a -> c

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

константы-дерева какую-нибудь часть или указать на какие константы мы реагируем в данном уравнении.

Ещё мы узнали о частичном применении. О том, что все функции в Haskell являются функциями одного

аргумента, которые возвращают константы или другие функции одного аргумента.

Мы потренировались в составлении неправильных выражений и посмотрели как компилятор на основе

правил применения узнаёт что они неправильные. Мы узнали, что такое ограничение мономорфизма и как

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

56 | Глава 3: Типы

Succ

not

Рис. 3.7: Конструкторы и синонимы

3.7 Упражнения

• Составьте в интерпретаторе как можно больше неправильных выражений и посмотрите на сообще-

ния об ошибках. Разберитесь почему выражение оказалось неправильным. Для этого проверьте типы с

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

мономорфизма.

• Потренируйтесь в интерпретаторе с функциями map, filter и foldr. Попробуйте их с самыми разными

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

упражнениях.

• В этой главе было много картинок и графических аналогий, попробуйте попрограммировать в картин-

ках. Нарисуйте определённые нами функции или какие-нибудь новые в виде деревьев. Например, это

можно сделать так. Мы будем отличать конструкторы от синонимов. Конструкторы будем рисовать в

одинарном кружке, а синонимы в двойном.

one

=

Nat

Succ

Zero

Рис. 3.8: Синоним-константа

Мы будем все функции писать также как и прежде, но вместо аргументов слева от знака равно и выра-

жений справа от знака равно, будем рисовать деревья.

Например, объявим простой синоним-константу (рис. 3.8). Мы будем дорисовывать сверху типы зна-

чений вместо объявления типа функции.

Несколько функций для списков. Извлечение первого элемента (рис. 3.9) и функция преобразования

всех элементов списка (рис. 3.10). Попробуйте в таком же духе определить несколько функций.

Упражнения | 57

head

[a]

=

a

:

x

x

Рис. 3.9: Функция извлечения первого элемента списка

map

a->b

[a]

=

[b]

[]

[]

f

map

a->b

[a]

=

[b]

:

:

f

x

xs

map

f

x

f

xs

Рис. 3.10: Функция преобразования элементов списка

58 | Глава 3: Типы

Глава 4

Декларативный и композиционный

стиль

В Haskell существует несколько встроенных выражений, которые облегчают построение функций и дела-

ют код более наглядным. Их можно разделить на два вида: выражения, которые поддерживают декларативный

стиль (declarative style) определения функций, и выражения которые поддерживают композиционный стиль

(expression style).

Что это за стили? В декларативном стиле определения функций больше похожи на математическую но-

тацию, словно это предложения языка. В композиционном стиле мы строим из маленьких выражений более

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

В Haskell есть полноценная поддержка и того и другого стиля, поэтому конструкции которые мы рас-

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

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

4.1 Локальные переменные

Вспомним формулу вычисления площади треугольника по трём сторонам:

S =

p · ( p − a) · ( p − b) · ( p − c)

Где a, b и c – длины сторон треугольника, а p это полупериметр.

Как бы мы определили эту функцию теми средствами, что у нас есть? Наверное, мы бы написали так:

square a b c = sqrt (p a b c * (p a b c - a) * (p a b c - b) * (p a b c - c))

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

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

C++: базовый курс
C++: базовый курс

В этой книге описаны все основные средства языка С++ - от элементарных понятий до супервозможностей. После рассмотрения основ программирования на C++ (переменных, операторов, инструкций управления, функций, классов и объектов) читатель освоит такие более сложные средства языка, как механизм обработки исключительных ситуаций (исключений), шаблоны, пространства имен, динамическая идентификация типов, стандартная библиотека шаблонов (STL), а также познакомится с расширенным набором ключевых слов, используемым в .NET-программировании. Автор справочника - общепризнанный авторитет в области программирования на языках C и C++, Java и C# - включил в текст своей книги и советы программистам, которые позволят повысить эффективность их работы. Книга рассчитана на широкий круг читателей, желающих изучить язык программирования С++.

Герберт Шилдт

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