`
Читать книги » Книги » Компьютеры и Интернет » Программирование » Миран Липовача - Изучай Haskell во имя добра!

Миран Липовача - Изучай Haskell во имя добра!

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

Loading package integer-gmp ... linking ... done.

Loading package base ... linking ... done.

Loading package ffi-1.0 ... linking ... done.

Prelude>

Поздравляю – вы в GHCi!

ПРИМЕЧАНИЕ. Приглашение консоли ввода – Prelude>, но поскольку оно может меняться в процессе работы, мы будем использовать просто ghci>. Если вы захотите, чтобы у вас было такое же приглашение, выполните команду :set prompt "ghci> ".

Немного школьной арифметики:

ghci> 2 + 15 17

ghci> 49 * 100

4900

ghci> 1892 – 1472 420

ghci> 5 / 2

2.5

Код говорит сам за себя. Также в одной строке мы можем использовать несколько операторов; при этом работает обычный порядок вычислений. Можно использовать и круглые скобки для облегчения читаемости кода или для изменения порядка вычислений:

ghci> (50 * 100) – 4999 1

ghci> 50 * 100 – 4999

1

ghci> 50 * (100 – 4999)

–244950

Здорово, правда? Чувствую, вы со мной не согласны, но немного терпения! Небольшая опасность кроется в использовании отрицательных чисел. Если нам захочется использовать отрицательные числа, то всегда лучше заключить их в скобки. Попытка выполнения 5 * –3 приведёт к ошибке, зато 5 * (–3) сработает как надо.

Булева алгебра в Haskell столь же проста. Как и во многих других языках программирования, в Haskell имеется два логических значения True и False, для конъюнкции используется операция && (логическое «И»), для дизъюнкции – операция || (логическое «ИЛИ»), для отрицания – операция not.

ghci> True && False False

ghci> True && True True

ghci> False || True True

ghci> not False

True

ghci> not (True&&True)

False

Можно проверить два значения на равенство и неравенство с помощью операций == и /=, например:

ghci> 5 == 5

True

ghci> 1 == 0

False

ghci> 5 /= 5

False

ghci> 5 /= 4

True

ghci> "привет" == "привет"

True

А что насчёт 5 + лама или 5 == True? Если мы попробуем выполнить первый фрагмент, то получим большое и страшное сообщение об ошибке[1]!

No instance for (Num [Char])

arising from a use of `+' at <interactive>:1:0–9

Possible fix: add an instance declaration for (Num [Char]) In the expression: 5 + "лама"

In the definition of `it': it = 5 + "лама"

Та-ак! GHCi говорит нам, что лама не является числом, и непонятно, как это прибавить к 5. Даже если вместо лама подставить четыре или 4, Haskell всё равно не будет считать это числом! Операция + ожидает, что аргументы слева и справа будут числовыми. Если же мы попытаемся посчитать True == 5, GHCi опять скажет нам, что типы не совпадают.

Несмотря на то что операция + производится только в отношении элементов, воспринимаемых как число, операция сравнения (==), напротив, применима к любой паре элементов, которые можно сравнить. Фокус заключается в том, что они должны быть одного типа. Вы не сможете сравнивать яблоки и апельсины. В подробностях мы это обсудим чуть позже.

ПРИМЕЧАНИЕ. Запись 5 + 4.0 вполне допустима, потому что 5 может вести себя как целое число или как число с плавающей точкой. 4.0 не может выступать в роли целого числа, поэтому именно число 5 должно «подстроиться».

Вызов функций

Возможно, вы этого пока не осознали, но всё это время мы использовали функции. Например, операция * – это функция, которая принимает два числа и перемножает их. Как вы видели, мы вызываем её, вставляя символ * между числами. Это называется «инфиксной записью».

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

ghci> succ 8 9

Функция succ принимает на вход любое значение, которое может иметь последующее значение, после чего возвращает именно последующее значение. Как вы видите, мы отделяем имя функции от параметра пробелом. Вызывать функции с несколькими параметрами не менее просто.

Функции min и max принимают по два аргумента, которые можно сравнивать (как и числа!), и возвращают большее или меньшее из значений:

ghci> min 9 10

9

ghci> min 3.4 3.2

3.2

ghci> max 100 101 101

Операция применения функции (то есть вызов функции с указанием списка параметров через пробел) имеет наивысший приоритет. Для нас это значит, что следующие два выражения эквивалентны:

ghci> succ 9 + max 5 4 + 1

16

ghci> (succ 9) + (max 5 4) + 1

16

Однако если мы хотим получить значение, следующее за произведением чисел 9 и 10, мы не можем написать succ 9 * 10, потому что это даст значение, следующее за 9 (т. е. 10), умноженное на 10, т. е. 100. Следует написать succ (9 * 10), чтобы получить 91.

Если функция принимает ровно два параметра, мы также можем вызвать её в инфиксной форме, заключив её имя в обратные апострофы. Например, функция div принимает два целых числа и выполняет их целочисленное деление:

ghci> div 92 10

9

Но если мы вызываем её таким образом, то может возникнуть неразбериха с тем, какое из чисел делимое, а какое делитель. Поэтому можно вызвать функцию в инфиксной форме, что, как оказывается, гораздо понятнее[2]:

ghci> 92 `div` 10

9

Многие люди, перешедшие на Haskell с императивных языков, придерживаются мнения, что применение функции должно обозначаться скобками. Например, в языке С используются скобки для вызова функций вроде foo(), bar(1) или baz(3, ха-ха). Однако, как мы уже отмечали, для применения функций в Haskell предусмотрены пробелы. Поэтому вызов соответствующих функций производится следующим образом: foo, bar 1 и baz 3 ха-ха. Так что если вы увидите выражение вроде bar (bar 3), это не значит, что bar вызывается с параметрами bar и 3. Это значит, что мы сначала вызываем функцию bar с параметром 3, чтобы получить некоторое число, а затем опять вызываем bar с этим числом в качестве параметра. В языке С это выглядело бы так: “bar(bar(3))”.

Функции: первые шаги

Определяются функции точно так же, как и вызываются. За именем функции следуют параметры[3], разделённые пробелами. Но при определении функции есть ещё символ =, а за ним – описание того, что функция делает. В качестве примера напишем простую функцию, принимающую число и умножающую его на 2. Откройте свой любимый текстовый редактор и наберите в нём:

doubleMe x = x + x

Сохраните этот файл, например, под именем baby.hs. Затем перейдите в каталог, в котором вы его сохранили, и запустите оттуда GHCi. В GHCi выполните команду :l baby. Теперь наш сценарий загружен, и можно поупражняться c функцией, которую мы определили:

ghci> :l baby

[1 of 1] Compiling Main     ( baby.hs, interpreted )

Ok, modules loaded: Main.

ghci> doubleMe 9

18

ghci> doubleMe 8.3

16.6

Поскольку операция + применима как к целым числам, так и к числам с плавающей точкой (на самом деле – ко всему, что может быть воспринято как число), наша функция одинаково хорошо работает с любыми числами. А теперь давайте напишем функцию, которая принимает два числа, умножает каждое на два и складывает их друг с другом. Допишите следующий код в файл baby.hs:

doubleUs x y = x*2 + y*2

ПРИМЕЧАНИЕ. Функции в языке Haskell могут быть определены в любом порядке. Поэтому совершенно неважно, в какой последовательности приведены функции в файле baby.hs.

Теперь сохраните файл и введите :l baby в GHCi, чтобы загрузить новую функцию. Результаты вполне предсказуемы:

ghci> doubleUs 4 9

26

ghci> doubleUs 2.3 34.2

73.0

ghci> doubleUs 28 88 + doubleMe 123

478

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

doubleUs x y = doubleMe x + doubleMe y

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

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

Откройте для себя мир чтения на siteknig.com - месте, где каждая книга оживает прямо в браузере. Здесь вас уже ждёт произведение Миран Липовача - Изучай Haskell во имя добра!, относящееся к жанру Программирование. Никаких регистраций, никаких преград - только вы и история, доступная в полном формате. Наш литературный портал создан для тех, кто любит комфорт: хотите читать с телефона - пожалуйста; предпочитаете ноутбук - идеально! Все книги открываются моментально и представлены полностью, без сокращений и скрытых страниц. Каталог жанров поможет вам быстро найти что-то по настроению: увлекательный роман, динамичное фэнтези, глубокую классику или лёгкое чтение перед сном. Мы ежедневно расширяем библиотеку, добавляя новые произведения, чтобы вам всегда было что открыть "на потом". Сегодня на siteknig.com доступно более 200000 книг - и каждая готова стать вашей новой любимой. Просто выбирайте, открывайте и наслаждайтесь чтением там, где вам удобно.

Комментарии (0)