52700.fb2 Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 73

Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 73

x@(Succ y) = (y, Succ x)

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

x(...)@ в англоязычной литературе принято называть as-patterns.

4.7 Упражнения

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

претаторе. Вызывайте их с различными значениями, экспериментируйте.

• Попробуйте определить функции из предыдущих глав в чисто композиционном стиле.

• Посмотрите на те функции, которые мы прошли и попробуйте переписать их определения шиворот

на выворот. Если вы видите, что элемент написан композиционном стиле перепишите его в деклара-

тивном и наоборот. Получившиеся функции могут показаться монстрами, но это упражнение может

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

иного стиля.

• Определите модуль, который будет вычислять площади простых фигур, треугольника, окружности,

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

• Поток это бесконечный список, или список, у которого нет конструктора пустого списка:

data Stream a = a :& Stream a

Так например мы можем составить поток из всех чисел Пеано:

nats :: Nat -> Stream Nat

nats a = a :& nats (Succ a)

Или поток, который содержит один и тот же элемент:

constStream :: a -> Stream a

constStream a = a :& constStream a

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

поскольку мы не сможем распечатать поток целиком (ведь он бесконечный):

-- Первый элемент потока

head :: Stream a -> a

-- Хвост потока, всё кроме первого элемента

tail :: Stream a -> Stream a

-- n-тый элемент потока

(!! ) :: Stream a -> Int -> a

-- Берёт из потока несколько первых элементов:

take :: Int -> Stream a -> [a]

Имена этих функций будут совпадать с именами функций для списков чтобы избежать коллизий имён

мы воспользуемся квалифицированным импортом функций. Делается это так:

import qualified Prelude as P( определения )

Слова qualified и as – ключевые. Теперь для использования функций из модуля Prelude мы будем писать

P.имяФункции. Такие имена называются квалифицированными. Для того чтобы пользоваться квалифициро-

ванными именами только для тех функций, для которых возможна коллизия имён можно поступить так:

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

import qualified Prelude as P

import Prelude

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

Для удобства тестирования можно определить такую функцию печати потоков:

instance Show a => Show (Stream a) where

show xs =

showInfinity (show (take 5 xs))

where showInfinity x = P. init x

P.++ ”...”

Функция P. init выделяет все элементы списка кроме последнего. В данном случае она откусит от строки

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