Учебник по Haskell - [19]

Шрифт
Интервал

(Succ Zero)

True

it :: Bool

Класс Num. Сложение и умножение

Сложение и умножение определены в классе Num. Посмотрим на его определение:

*Nat> :i Num

class (Eq a, Show a) => Num a where

(+) :: a -> a -> a

(*) :: a -> a -> a

(-) :: a -> a -> a

negate :: a -> a

abs :: a -> a

signum :: a -> a

fromInteger :: Integer -> a

-- Defined in GHC.Num

Методы (+), (*), (-) в представлении не нуждаются, метод negate является унарным минусом, его можно

определить через (-) так:

32 | Глава 2: Первая программа

negate x = 0 - x

Метод abs является модулем числа, а метод signum возвращает знак числа, метод fromInteger позволяет

создавать значения данного типа из стандартных целых чисел Integer.

Этот класс устарел, было бы лучше сделать отельный класс для сложения и вычитания и отдельный

класс для умножения. Также контекст класса, часто становится помехой. Есть объекты, которые нет смысла

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

написанным кодом, класс Num остаётся прежним.

Определим экземпляр для чисел Пеано, но давайте сначала разберём функции по частям.

Сложение

Начнём со сложения:

instance Num Nat where

(+) a Zero

= a

(+) a (Succ b) = Succ (a + b)

Первое уравнение говорит о том, что, если второй аргумент равен нулю, то мы вернём первый аргумент

в качестве результата. Во втором уравнении мы “перекидываем” конструктор Succ из второго аргумента за

пределы суммы. Схематически вычисление суммы можно представить так:

3+2 1 + (3+1) 1 + (1 + (3+0))

1 + (1 + 3) 1 + (1 + (1 + (1 + (1 + 0)))) 5

Все наши числа имеют вид 0 или 1+ n, мы принимаем на вход два числа в таком виде и хотим в результате

составить число в этом же виде, для этого мы последовательно перекидываем $(1+) в начало выражения из

второго аргумента.

Вычитание

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

String -> a, она принимает строку с сообщением об ошибке, при её вычислении программа остановит-

ся с ошибкой и сообщение будет выведено на экран.

negate _ = error ”negate is undefined for Nat”

Умножение

Теперь посмотрим на умножение:

(*) a Zero

= Zero

(*) a (Succ b) = a + (a * b)

В первом уравнении мы вернём ноль, если второй аргумент окажется нулём, а во втором мы за каждый

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

ния a * b мы получим аргумент a сложенный b раз. Это и есть умножение. При этом мы воспользовались

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

3*2 3 + (3*1) 3 + (3 + (3*0)) 3 + (3+0) 3+3

1 + (3+2) 1 + (1 + (3+1)) 1 + (1 + (1 + (3+0)))

1 + (1 + 1 + 3) 1 + (1 + (1 + (1 + (1 + (1 + 0))))) 6

Операции abs и signum

Поскольку числа у нас положительные, то методы abs и signum почти ничего не делают:

abs

x

= x

signum Zero = Zero

signum _

= Succ Zero

Арифметика | 33

Перегрузка чисел

Остался последний метод fromInteger. Он конструирует значение нашего типа из стандартного:

fromInteger 0 = Zero

fromInteger n = Succ (fromInteger (n-1))

Зачем он нужен? Попробуйте узнать тип числа 1 в интерпретаторе:

*Nat> :t 1

1 :: (Num t) => t

Интерпретатор говорит о том, тип значения 1 является некоторым типом из класса Num. В Haskell обозна-

чения для чисел перегружены. Когда мы пишем 1 на самом деле мы пишем (fromInteger (1::Integer)).

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

сохраним определение экземпляра для Num и загрузим обновлённый модуль в интерпретатор:

[1 of 1] Compiling Nat

( Nat. hs, interpreted )

Ok, modules loaded: Nat.

*Nat> 7 :: Nat

Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero))))))

*Nat> (2 + 2) :: Nat

Succ (Succ (Succ (Succ Zero)))

*Nat> 2 * 3 :: Nat

Succ (Succ (Succ (Succ (Succ (Succ Zero)))))

Вы можете убедиться насколько гибкими являются числа в Haskell:

*Nat> (1 + 1) :: Nat

Succ (Succ Zero)

*Nat> (1 + 1) :: Double

2.0

*Nat> 1 + 1

2

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

последнем выражении тип был приведён к Integer. Это поведение интерпретатора по умолчанию. Если мы

напишем:

*Nat> let q = 1 + 1

*Nat> :t q

q :: Integer

Мы видим, что значение q было переведено в Integer, это происходит лишь в интерпретаторе, если такая

переменная встретится в программе и компилятор не сможет определить её тип из контекста, произойдёт

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

добавив объявление типа с помощью конструкции (v :: T).

Посмотрим ещё раз на определение экземпляра Num для Nat целиком:

instance Num Nat where

(+) a Zero

= a

(+) a (Succ b) = Succ (a + b)

(*) a Zero

= Zero

(*) a (Succ b) = a + (a * b)

fromInteger 0 = Zero

fromInteger n = Succ (fromInteger (n-1))

abs

x

= x

signum Zero = Zero

signum _

= Succ Zero

negate _ = error ”negate is undefined for Nat”

34 | Глава 2: Первая программа

Класс Fractional. Деление

Деление определено в классе Fractional:

*Nat>:m Prelude

Prelude> :i Fractional

class Num a => Fractional a where

(/) :: a -> a -> a

recip :: a -> a

fromRational :: Rational -> a

-- Defined in ‘GHC.Real’


Рекомендуем почитать
Уголовное право. Особенная часть

В книге кратко изложены ответы на основные вопросы темы «Уголовное право. Особенная часть». Издание поможет систематизировать знания, полученные на лекциях и семинарах, подготовиться к сдаче экзамена или зачета.Пособие адресовано студентам высших и средних образовательных учреждений, а также всем интересующимся данной тематикой.


Уголовно-исполнительное право

В книге кратко изложены ответы на основные вопросы темы «Уголовно-исполнительное право». Издание поможет систематизировать знания, полученные на лекциях и семинарах, подготовиться к сдаче экзамена или зачета.Пособие адресовано студентам высших и средних образовательных учреждений, а также всем интересующимся данной тематикой.


Самоучитель Adobe Premiere 6.5

Книга посвящена возможностям самого популярного средства цифрового видеомонтажа – Adobe Premiere 6.5. Описываются основные приемы работы с программой, приводятся сведения об управлении проектами и клипами, обсуждаются методы монтажа видео и звука, техника создания титров и добавления спецэффектов, а также освещается процесс окончательного монтирования фильма. На примерах рассматриваются все этапы создания и обработки фильмов для телевидения, видео и мультимедиа.Для широкого круга пользователей.


Финансовое право

В учебном пособии в краткой и доступной форме рассмотрены все основные вопросы, предусмотренные государственным образовательным стандартом и учебной программой по дисциплине «Финансовое право».Книга позволит быстро получить основные знания по предмету, а также качественно подготовиться к зачету и экзамену.Рекомендуется студентам, аспирантам и преподавателям по юридическим, экономическим и управленческим специальностям, а также сотрудникам банков.Автор книги, Шевчук Денис Александрович, имеет опыт преподавания различных дисциплин в ведущих ВУЗах Москвы (экономические, юридические, технические, гуманитарные), два высших образования (экономическое и юридическое), более 30 публикаций (статьи и книги), Член Союза Юристов Москвы, Член Союза Журналистов России, Член Союза Журналистов Москвы, Стипендиат Правительства РФ, опыт работы в банках, коммерческих и государственных структурах (в т.ч.


фгос  ответы

Содержащиеся в пособии контрольно-измерительные материалы (КИМы) для 5 класса, аналогичные материалам ЕГЭ, составлены в соответствии с программой общеобразовательных учреждений по русскому языку и учитывают возрастные особенности учащихся. В конце пособия даны ответы на все варианты тестов, предложены диктанты различных типов.Пособие адресовано учителям, ученикам, их родителям и всем, кому необходимо закрепить и систематизировать знания перед ЕГЭ.


Теория литературы. Чтение как творчество

Цель предлагаемого пособия – систематизировать и обогатить представления о природе, структуре и особенностях художественной литературы как вида искусства, помочь совершенствованию читательского мастерства. Книга снабжена кратким словарем основных литературоведческих понятий и терминов (составлен при участии доцента О.В. Быстровой).Для студентов филологических факультетов, учителей, преподавателей литературы высших и средних учебных заведений.