Изучай Haskell ради Добра! Начало

Miran Lipovača, “Learn you a Haskell for Great Good:chapter - Starting-out”, public translation into Russian from English More about this translation.

Translate into another language.

Начало

На старт, внимание, марш!

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

Первое, что мы сделаем – это запустим GHC в интерактивном режиме, и вызовем несколько функций, чтобы почувствовать Haskell. Откройте консоль и наберите ghci. Вы увидите примерно такое приветствие:

GHCi, version 6.8.2: http://www.haskell.org/ghc/ :? for help

Loading package base ... 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>

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

ghci> (50 * 100) - 4999

1

ghci> 50 * 100 - 4999

1

ghci> 50 * (100 - 4999)

-244950

Здорово, да? Да, я знаю, что это не так, но немного терпения. Небольшая опасность кроется в использовании отрицательных чисел. Если нам захочется использовать отрицательные числа, то всегда лучше обернуть их в скобки. Попытка выполнения «5 * -3» приведет к ошибке, а «5 * (-3)» отработает нормально.

Булева алгебра также очень прямолинейна. Как вы, возможно, знаете, «&&» – означает логическое «И», «||» – логическое «ИЛИ», а «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> "hello" == "hello"

True

А как насчет «5 + "llama"» или «5 == True»? Так, если мы попробуем выполнить первый фрагмент, то получим большое и страшное сообщение об ошибке!

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 + "llama"

In the definition of `it': it = 5 + "llama"

Ой! GHCi говорит нам, что "llama" не является числом, и он (GHCi) не знает, как это прибавить к 5. Даже если бы это было не "llama", а "four" или "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. То есть, 100. Нам надо написать «succ (9 * 10)», чтобы получить 91.

Если функция принимает два параметра, мы также можем вызвать её в инфиксной форме, окружив её имя обратными апострофами. Например, функция «div» принимает два челых числа и выполняет их целочисленное деление. «div 92 10» возвращает 9. Но если мы вызываем её так, то может возникнуть некоторое недопонимание, какое из чисел – делимое, а какое – делитель. Поэтому мы можем вызвать функцию в инфиксной форме: «92 `div` 10», что, как оказывается, гораздо понятнее.

Многие люди, пришедшие с императивных языков, обычно, придерживаются мнения, что применение функции должно обозначаться скобками. Например, в Си используются скобки для вызова функций вроде «foo()», «bar(1)» или «baz(3, "haha")». Как мы уже сказали, для применения функций в Haskell используются пробелы.

Вызов этих функций в Haskell будет выглядеть как «foo», «bar 1» и «baz 3 "haha"». Так что, если вы увидите нечто вроде «bar (bar 3)», это не значит, что bar вызывается с параметрами bar и 3. Это значит, что мы сначала вызываем функцию bar с параметром 3, чтобы получить некоторое число, а затем опять вызываем bar с этим числом в качестве параметра. В языке Си это выглядело бы как "bar(bar(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

Поскольку «+» работает как на целых числах, так и на числах с плавающей точкой (на самом деле, на всём, что может быть воспринято как число), поэтому наша функция одинаково хорошо работает с любыми числами. Давайте сделаем функцию, которая принимает два числа, умножает каждое на 2 и результат складывает.

doubleUs x y = x*2 + y*2

Все просто. Мы также могли определить эту функцию как «doubleUs x y = x + x + y + y». Если её потестировать - она выдает хорошо предсказуемые результаты (не забудьте дописать эту функцию в файл «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

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

Подобный подход, также, позволяет избежать дублирования кода. Например, если какие-нибудь «математики» вывели бы, что 2 – это на самом деле 3 и вам нужно изменить свою программу? Вы бы могли просто переопределить doubleMe как «x + x + x», и поскольку doubleUs вызывает doubleMe, она бы автоматически работала в этом странном мире, где 2 – это 3.

Pages: ← previous Ctrl next
1 2 3 4

Original (English): Learn you a Haskell for Great Good:chapter - Starting-out

Translation: © ventalf, Dmitry-Leushin, siasia, Николай, artobstrel95, dr15x86, slayzx, spiritrc, butry, Руслан Гроховецкий, Kostafey .

License: Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License

translated.by crowd

Like this translation? Share it or bookmark!