Мы уже написали несколько полезных функций для работы с точками и, в принципе, поняли, как работает эта абстракция. Теперь пришло время копнуть на уровень глубже и посмотреть, как же устроены наши точки.
<?php
use function Php\Pairs\Pairs\cons;
use function Php\Pairs\Pairs\car;
use function Php\Pairs\Pairs\cdr;
// Конструктор
$pair = cons(8, 7);
car($pair); // 8
cdr($pair); // 7
$pair2 = cons(3, $pair);
Устроены они достаточно просто и используют структуру данных, которая называется парой. Пар в самом языке PHP не существует, мы их реализовали с помощью отдельной библиотеки, и выше можно увидеть пример того, как они используются. Мы подключаем из библиотеки конструктор cons
и селекторы car
и cdr
. Конструктор создает пару, а селекторы служат для извлечения из пары первого значения (с помощью car
) и второго значения (с помощью cdr
). Всё достаточно просто и очень похоже на реализацию точек из прошлого урока.
Что интересно, элементами пары могут быть другие пары. В будущем это даст нам очень мощные возможности для того, чтобы строить более сложные структуры данных, в том числе списковые.
Давайте посмотрим, как представлены наши точки с помощью пар:
<?php
use function Php\Pairs\Pairs\cons;
use function Php\Pairs\Pairs\car;
use function Php\Pairs\Pairs\cdr;
use function Php\Pairs\Pairs\toString as pairToString;
function makePoint($x, $y)
{
return cons($x, $y);
}
function getX($point)
{
return car($point);
}
function getY($point)
{
return cdr($point);
}
function toString($point)
{
return pairToString($point);
}
Здесь всё предельно просто: makePoint
— это функция, которая принимает $x
и $y
и вызывает конструктор пары с этими аргументами. То же самое с селекторами: getX
и getY
принимают на вход точку и вызывают с этой точкой car
и cdr
соответственно.
Теперь, используя пары, мы можем создавать новые абстракции, расширяя нашу библиотеку графических примитивов. Мы вводим понятие отрезка, для которого мы создаём конструктор и селекторы:
<?php
$point1 = makePoint(1, 2);
$point2 = makePoint(10, -2);
$segment = makeSegment($point1, $point2);
startSegment($segment); // (1, 2)
endSegment($segment); // (10, -2)
Нам нужно сделать две точки (потому что любой отрезок представлен двумя точками). После этого мы используем конструктор makeSegment
и передаём туда наши точки, а с помощью селекторов startSegment
и endSegment
мы получаем точки. Важно, что мы получаем именно точки, потому что это тоже составные данные со своими селекторами, с помощью которых можно получать примитивные значения и производить над ними какие-либо манипуляции при необходимости.
Песочница
<?php
require_once ('lib.php');
$pair = \Php\Pairs\Pairs\cons('first', 'second');
print_r(\Php\Pairs\Pairs\car($pair)); // => first
print_r("\n");
print_r(\Php\Pairs\Pairs\cdr($pair)); // => second
print_r("\n");
print_r($pair); // don't do it
// => Closure Object
// => (
// => [static] => Array
// => (
// => [x] => first
// => [y] => second
// => )
// =>
// => [parameter] => Array
// => (
// => [$method] => <required>
// => )
// =>
// => )
https://repl.it/@hexlet/php-compound-data-pair
Пары
Обратите внимание на то, что пары неизменяемы. Нельзя просто так взять и изменить пару. Можно только создать новую на основе предыдущей. Поначалу такой способ программирования может показаться необычным и сложным, так как надо перестроить своё мышление. Чем дальше вы будете продвигаться по курсам, тем больше он вам начнёт нравиться. Вы увидите, как часто упрощается код и его отладка в отсутствие изменяемости.
Дополнительные материалы
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.