Изучай Haskell ради Добра! Начало |
- Statistics
- Participants
- Translate into Russian
- Translation result
- Translation complete.
Начало
На старт, внимание, марш!
Отлично, давайте начнем! Если вы из тех ужасных людей, что не читают введение и просто пропускают его, то вам все равно стоит заглянуть в его заключительную часть, так как именно там объясняется то, что вам потребуется при прочтении данного руководства и что необходимо для загрузки программ.
Первое, что мы сделаем – это запустим 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.
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
