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

class AdditiveGroup v => VectorSpace v where

type Scalar v

:: *

(*^)

:: Scalar v -> v -> v

Линейное пространство это математическая структура, объектами которой являются вектора и скаля-

ры. Для векторов определена операция сложения, а для скаляров операции сложения и умножения. Кроме

того определена операция умножения вектора на скаляр. При этом должны выполнятся определённые свой-

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

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

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

двойное двоеточие мы указываем его вид. В данном случае это простой тип без параметров.

Вид (kind) это тип типа. Простой тип без параметра обозначается звёздочкой. Тип с параметром обозна-

чается как функция * -> *. Если бы тип принимал два параметра, то он обозначался бы * -> * -> *. Также

параметры могут быть не простыми типами а типами с параметрами, например тип, который обозначает

композицию типов:

newtype O f g a = O { unO :: f (g a) }

имеет вид (* -> *) -> (* -> *) -> * -> *.

Определим класс векторов на двумерной сетке и сделаем его экземпляром класса VectorSpace. Для нача-

ла создадим новый модуль с активным расширением TypeFamilies и запишем в него классы для линейного

пространства

{-# Language TypeFamilies #-}

module Point2D where

class AdditiveGroup v where

...

Теперь определим новый тип:

data V2 = V2 Int Int

deriving (Show, Eq)

Сделаем его экземпляром класса AdditiveGroup:

instance AdditiveGroup V2 where

zeroV

= V2 0 0

(V2 x y)

^+^ (V2 x’ y’)

= V2 (x+x’) (y+y’)

negateV (V2 x y)

= V2 (-x) (-y)

Мы складываем и вычитаем значения в каждом из элементов кортежа. Нейтральным элементом от-

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

VectorSpace. Поскольку кортеж состоит из двух целых чисел, скаляр также будет целым числом:

instance VectorSpace V2 where

type Scalar V2 = Int

s *^ (V2 x y) = V2 (s*x) (s*y)

Попробуем вычислить что-нибудь в интерпретаторе:

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

*Prelude> :l Point2D

[1 of 1] Compiling Point2D

( Point2D. hs, interpreted )

Ok, modules loaded: Point2D.

*Point2D> let v =

V2 1 2

*Point2D> v ^+^ v

V2 2 4

*Point2D> 3 *^ v ^+^ v

V2 4 8

*Point2D> negateV $ 3 *^ v ^+^ v

V2 (-4) (-8)

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

сический пример. Реализуем в типах числа Пеано. Нам понадобятся два типа. Один для обозначения нуля,

а другой для обозначения следующего элемента:

{-# Language TypeFamilies, EmptyDataDecls #-}

module Nat where

data Zero

data Succ a

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

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

рации сложения и умножения для чисел. Для начала определим сложение:

type family Add a b :: *

type instance Add a Zero

= a

type instance Add a (Succ b)

= Succ (Add a b)

Первой строчкой мы определили семейство функций Add, у которого два параметра. Определение семей-

ства типов начинается с ключевой фразы type family. За двоеточием мы указали тип семейства. В данном

случае это простой тип без параметра. Далее следуют зависимости типов для семейства Add. Зависимости

типов начинаются с ключевой фразы type instance. В аргументах мы словно пользуемся сопоставлением с

образцом, но на этот раз на типах. Первое уравнение:

type instance Add a Zero

= a

Говорит о том, что если второй аргумент имеет тип ноль, то мы вернём первый аргумент. Совсем как в

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

составляем рекурсивное уравнение:

type instance Add a (Succ b)

= Succ (Add a b)

Точно также мы можем определить и умножение:

type family Mul a b :: *

type instance Mul a Zero

= Zero

type instance Mul a (Succ b)

= Add a (Mul a b)

При этом нам придётся подключить ещё одно расширение UndecidableInstances, поскольку во втором

уравнении мы подставили одно семейство типов в другое. Этот флаг часто используется в сочетании с рас-

ширением TypeFamilies. Семейства типов фактически позволяют нам определять функции на типах. Это

ведёт к тому, что алгоритм вывода типов становится неопределённым. Если типы правильные, то компиля-

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

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

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

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

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

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

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

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

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