Skip to content

Latest commit

 

History

History
209 lines (160 loc) · 12.1 KB

Starting_out_with_Racket.org

File metadata and controls

209 lines (160 loc) · 12.1 KB

Начинаем с Racket

Начинаем с Racket

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

Функции в математике

Вот два простых математических определения.

\[ f(x) = x^2 \] \[ g(x, y) = x + y \]

\(f\) это функция, которая возводит число в квадрат, а \(g\) — функция сложения. На деле мы вряд ли стали бы давать имена этим двум функциям, т. к. у нас уже есть способ записи этих действий, как видно справа от знака равенства. Два этих простых примера не очень показательны, они нужны лишь для того, чтобы отразить суть.

Эти два определения построены схожим образом. Сначала идёт имя функции, \(f\) и \(g\) соответственно. После имени функции идут имена параметров функции, разделённые запятыми и заключённые в круглые скобки.

Дальше идёт знак равенства \(=\), означающий “определяется как”. За знаком равенства следует тело функции — некоторое выражение с использованием имён параметров.

После того как определения даны, можно использовать или применять эти функции к конкретным аргументам, как в следующем примере.

\begin{align*} g(1, 3) &= 1 + 3
&= 4 \end{align*}

Выражение \(g(1, 3)\) означает, что первый параметр \(g\) (которому было дано имя \(x\) в определении) должен иметь значение \(1\), а второй параметр (с именем \(y\)) должен иметь значение \(3\). Чтобы вычислить значение \(g(1, 3)\), мы подставляем \(1\) вместо \(x\) и \(3\) вместо \(y\) в выражении \(x + y\) из определения \(g\), и получаем выражение \(1 + 3\). После чего выполняем действие сложения и получаем результат — значение \(4\).

Применения функций можно вкладывать друг в друга, что приводит к более сложным выражениям типа \(g(g(1, 3), f(2))\). В данном случае мы можем выбрать, в каком порядке подставлять и выполнять.

Вот один вариант.

\begin{align*} g(g(1, 3), f(2)) &= g(4, f(2))
&= g(4, 4) \ &= 4 + 4 \ &= 8 \end{align*}

А вот другой.

\begin{align*} g(g(1, 3), f(2)) &= g(1, 3) + f(2)
&= 4 + f(2) \ &= 4 + 4 \ &= 8 \end{align*}

Порядок выполнения здесь неважен (результат один и тот же), но в Racket, когда появятся другие языковые возможности, это может иметь значение.

Применение функции в Racket

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

В применении функции в Racket имя функции расположено после открывающей скобки, а не перед ней, и аргументы отделяются друг от друга пробелами, а не запятыми.

\(g(1, 3)\) становится, в Racket, src_lisp[:exports code]{(g 1 3)}

\(g(g(1, 3), f(2))\) превращается в src_lisp[:exports code]{(g (g 1 3) (f 2))}

В арифметических выражениях мы, как правило, помещаем оператор между операндами: \(3 - 2 + 4 / 5\), а когда мы применяем функцию, ставим имя функции перед её аргументами. В школе дети запоминают правила, определяющие порядок выполнения операций при упрощении выражений (действия выполняются слева направо, а деление и умножение выполняются раньше сложения и вычитания). Иногда этих правил оказывается недостаточно, и нужно использовать скобки для группировки: \((6 - 4) / (5 + 7)\).

Мы могли бы использовать функциональную нотацию для таких операций как \(+\), считая их именованными функциям, а не операторами. Тогда бы выражение \(3 - 2 + 4 / 5\) превратилось в \(+(-(3, 2), /(4, 5))\). Теперь скобки используются только для того, чтобы соотносить аргументы с операциями, т. к. для упорядочивания они больше не нужны.

Именно это и сделано в Racket. Математические операторы становятся функциями в Racket. Скобки используются только для того, чтобы соотносить аргументы с операциями, а порядок выполнения определяется вложенностью.

\(3 - 2 + 4 / 5\) превращается в (+ (- 3 2) (/ 4 5))

\((6 - 4) (3 + 2)\) превращается в (* (- 6 4) (+ 3 2))

(Обратите внимание на то, что функция умножения называется *, а не \(×\); такой выбор обусловлен исторически — на первых компьютерах набор доступных символов был довольно ограниченным.)

Любое арифметическое выражение можно таким образом перевести в выражение на языке Racket. Но следует помнить, что лишние скобки добавлять не надо. В арифметических выражениях лишние скобки безвредны, но в Racket из-за них возникнут проблемы. Используйте скобки только тогда, когда они необходимы (например, чтобы записать применение функции).

Мы только начали изучать синтаксис Racket, но уже узнали достаточно, чтобы начать работу с самОй программой.

Интерактивное окно DrRacket

Если Вы ещё этого не сделали, то установите Racket с https://www.racket-lang.org, а затем откройте программу DrRacket. На самом деле, Racket это целое семейство языков, и в программе Вам предложат выбрать один из них; выберите Beginning Student Language (BSL). Это самый первый из серии языков, разработанных для обучения. Они предоставляют небольшие, но довольно мощные наборы языковых возможностей, что позволяет создавать более ясные сообщения об ошибках.

В DrRacket Вы увидите два окна, расположенных друг над другом; верхнее называется окном определений, а нижнее — интерактивным окном. Мы для начала сосредоточимся на нижнем, интерактивном, окне. В нём Вы увидите приглашение (prompt), выглядящее как > и обозначающее место, в которое Вы можете вписывать выражения, а затем выполнять их.

> (+ (* 3 3) (* 4 4))
25

Racket, в отличие от большинства языков программирования, представляет рациональные числа с неограниченной точностью.

> (/ (expt 6 40) (expt 2 90))
10798.17609466798060768866207581595517694950103759765625

Некоторые операции создают неточные или комплексные числа.

> (sqrt 2)
#i1.4142135623730951
> (sqrt -9)
0+3i

Неточные числа это рациональные приближения с фиксированной точностью. Они получаются тогда, когда результат выполнения операции нельзя представить полностью в виде рационального числа, как в случае с корнем из \(2\). Мы их использовать не будем, но у них есть своё применение, особенно в научных вычислениях (например, в физических симуляциях, где положение объекта, действующего под воздействием сил, постоянно обновляется, и хранить его с полной точностью значит хранить асбурдное количество ненужных цифр). Также мы не будем пользоваться комплексными числами, хотя Вы можете поэкспериментировать с ними, если хотите.

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

Упражнение 0. Каждое из следующих выражений вызовет ошибку при попытке его выполнить в DrRacket. Подумайте, что не так с каждым из этих выражений. Затем выполните их через интерактивное окно, чтобы увидеть ошибки, которые сгенерирует Racket.

  • (* (5) 3)
  • (+ (* 2 4))
  • (5 * 14)
  • (* + 3 5 2)
  • (/ 25 0)

\(\blacksquare\)

Определение функции в Racket