[Разработка веб-сайтов, PHP, Программирование] Tagged Unions в PHP (примерно как в Rust)
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
В предыдущей статье я писал про добавление enums в PHP8.1. Голосование прошло успешно, так что можно считать, что вопрос решенный.
Однако та реализация enums — лишь часть глобального плана. Сегодня мы рассмотрим следующий пункт, tagged unions, по-русски это переводится как "тип-сумма".
Голосования по нему пока не проходило, но предлагается также включить его в PHP 8.1.
Все эти термины "алгебраические типы данных", "тип-сумма" звучат страшно, но на деле всё довольно просто.
Зачем всё это вообще нужно?
Result как в Расте
Если вы писали на языке Rust, то наверняка встречали встроенный enum Result. В Rust, Go и т.д. нет механизма exception, так как в этих языках считается, что явная обработка ошибок гораздо надёжнее. Язык вынуждает тебя явно проработать все варианты событий, а не кидать исключение в надежде, что кто-то наверху знает о нём и умеет правильно обрабатывать. (Не будем здесь холиварить, на тему exceptions vs return type, у каждого своё мнение). Если говорить конкретно про Раст, то результатом вызова функции, которая может породить ошибку, часто делают значение типа Result.
Result состоит из двух вариантов (case-ов в терминологии enum в PHP): Ok и Err. Варианты мы могли бы сделать и с помощью предыдущего функционала enum, или даже констант, но нам нужно возвращать еще и сами значения. Причем, в случае успеха значением может быть строка, а в случае ошибки какой-нибудь другой тип. Например, integer (статус HTTP-ответа).
Как это будет выглядеть в PHP, если голосование будет успешным:
enum Result {
case Ok(public string $json);
case Err(public int $httpStatus);
}
function requestApi($url): Result {
//
}
теперь мы этот ответ можем передать куда-то еще, и знания об ошибке и ее типе никогда не пропадут.
Как я писал в предыдущей статье, enum — это по сути класс, в нём могут быть методы и т.д. В случае тип-суммы методы могут быть как общими на весь enum, так и на конкретный case.
Вот пример реализации монады Maybe (пример из RFC):
Монада Maybe
(В Расте такой тип называется Option)
enum Maybe {
// This is a Unit Case.
case None {
public function bind(callable $f)
{
return $this;
}
};
// This is a Tagged Case.
case Some(private mixed $value) {
// Note that the return type can be the Enum itself, thus restricting the return
// value to one of the enumerated types.
public function bind(callable $f): Maybe
{
// $f is supposed to return a Maybe itself.
return $f($this->value);
}
};
// This method is available on both None and Some.
public function value(): mixed {
if ($this instanceof None) {
throw new Exception();
}
return $this->val;
}
}
Как вы видите, в этом енаме два варианта: Some и None, причем Some имеет привязанное значение, а None — просто None. У каждого из вариантов может быть своя реализация метода bind. И также общий метод value()
В RFC не описано, но вызываться методы должны примерно также
$a = Maybe::Some("blabla");
// или $a = Maybe::None
$a->bind();
Естественно, просто передавать туда-сюда Result или Maybe смысла нет, нужно где-то всё же обработать это дело. Для этого хорошо подойдет pattern matching, на который уже есть RFC, но он сыроватый. Если включить фантазию, то выглядеть это будет примерно так:
$result = requestApi($url);
if ($result is Result::Some {%$json}) {
// выводим $json
}
if ($result is Result::Err {%$httpStatus}) {
// выводим $httpStatus
}
или примерно тоже самое, но с оператором match.
Еще пример
Есть куча вещей, которые будет удобнее программировать с tagged unions. Например, если кто-то писал парсер, то знает, что первым этапом идет tokenizer (scanner), который разбивает исходный код на токены. Вот тут прямо очень хорошо ложится: есть некий ограниченный набор видов токенов, который можно поместить в enum. Причем некоторые токены, например, строковый литерал или идентификатор, будут содержать еще и значение. В коде будет всё очень удобно и наглядно. Примерно так:
enum Token {
case Comma;
case LeftBrace;
case RightBrace;
case StringLiteral(public string $str);
case Identifier(public string $identifier);
// и т.д.
}
Что дальше?
Неизвестно, примут этот RFC на голосовании или нет, возможно посчитают, что это переусложнит язык и не нужно. Однако тенденция на усиление типизации, а также на перенятие синтаксических "фишек" из других языков налицо. Если примут tagged unions, то я готов поспорить, примут и pattern matching.
Если вам интересны подобные статьи про разработку, в частности, что будет дальше с паттерн матчингом, подписывайтесь на телеграм-канал Cross Join!
===========
Источник:
habr.com
===========
Похожие новости:
- [Программирование, Java] Вы часто используете null? А он у нас в спецификации
- [Разработка веб-сайтов, CSS] Минимальный размер содержимого в CSS Grid (перевод)
- [Разработка веб-сайтов, Управление продуктом, Логические игры] Пока в мире гремел сериал «Ход королевы», мы пилили сервис, чтобы дети учились шахматам на удобной платформе
- [JavaScript, Программирование, Учебный процесс в IT] Решение забавной задачки на JavaScript (перевод)
- [Open source, PHP, Symfony, Yii, Laravel] Package Wizard — незаменимый помощник при разработке веб-приложений
- [Разработка веб-сайтов, JavaScript, Программирование, .NET] Рабочий прототип секретного мессенджера
- [Программирование, Java] Шпаргалка по Spring Boot WebClient (перевод)
- [Ненормальное программирование, Разработка веб-сайтов, JavaScript, Программирование] Зачем мы используем addEventListener вместо onclick?
- [Программирование, DevOps, Kubernetes] Круглый стол «Нужно ли разработчику знать Kubernetes» 11 февраля
- [Программирование, Java, Совершенный код, Проектирование и рефакторинг, Kotlin] Свойства против методов
Теги для поиска: #_razrabotka_vebsajtov (Разработка веб-сайтов), #_php, #_programmirovanie (Программирование), #_php, #_tagged_unions, #_tipsumma (тип-сумма), #_razrabotka_vebsajtov (
Разработка веб-сайтов
), #_php, #_programmirovanie (
Программирование
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 17:04
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
В предыдущей статье я писал про добавление enums в PHP8.1. Голосование прошло успешно, так что можно считать, что вопрос решенный. Однако та реализация enums — лишь часть глобального плана. Сегодня мы рассмотрим следующий пункт, tagged unions, по-русски это переводится как "тип-сумма". Голосования по нему пока не проходило, но предлагается также включить его в PHP 8.1. Все эти термины "алгебраические типы данных", "тип-сумма" звучат страшно, но на деле всё довольно просто. Зачем всё это вообще нужно? Result как в Расте Если вы писали на языке Rust, то наверняка встречали встроенный enum Result. В Rust, Go и т.д. нет механизма exception, так как в этих языках считается, что явная обработка ошибок гораздо надёжнее. Язык вынуждает тебя явно проработать все варианты событий, а не кидать исключение в надежде, что кто-то наверху знает о нём и умеет правильно обрабатывать. (Не будем здесь холиварить, на тему exceptions vs return type, у каждого своё мнение). Если говорить конкретно про Раст, то результатом вызова функции, которая может породить ошибку, часто делают значение типа Result. Result состоит из двух вариантов (case-ов в терминологии enum в PHP): Ok и Err. Варианты мы могли бы сделать и с помощью предыдущего функционала enum, или даже констант, но нам нужно возвращать еще и сами значения. Причем, в случае успеха значением может быть строка, а в случае ошибки какой-нибудь другой тип. Например, integer (статус HTTP-ответа). Как это будет выглядеть в PHP, если голосование будет успешным: enum Result {
case Ok(public string $json); case Err(public int $httpStatus); } function requestApi($url): Result { // } теперь мы этот ответ можем передать куда-то еще, и знания об ошибке и ее типе никогда не пропадут. Как я писал в предыдущей статье, enum — это по сути класс, в нём могут быть методы и т.д. В случае тип-суммы методы могут быть как общими на весь enum, так и на конкретный case. Вот пример реализации монады Maybe (пример из RFC): Монада Maybe (В Расте такой тип называется Option) enum Maybe {
// This is a Unit Case. case None { public function bind(callable $f) { return $this; } }; // This is a Tagged Case. case Some(private mixed $value) { // Note that the return type can be the Enum itself, thus restricting the return // value to one of the enumerated types. public function bind(callable $f): Maybe { // $f is supposed to return a Maybe itself. return $f($this->value); } }; // This method is available on both None and Some. public function value(): mixed { if ($this instanceof None) { throw new Exception(); } return $this->val; } } Как вы видите, в этом енаме два варианта: Some и None, причем Some имеет привязанное значение, а None — просто None. У каждого из вариантов может быть своя реализация метода bind. И также общий метод value() В RFC не описано, но вызываться методы должны примерно также $a = Maybe::Some("blabla");
// или $a = Maybe::None $a->bind(); Естественно, просто передавать туда-сюда Result или Maybe смысла нет, нужно где-то всё же обработать это дело. Для этого хорошо подойдет pattern matching, на который уже есть RFC, но он сыроватый. Если включить фантазию, то выглядеть это будет примерно так: $result = requestApi($url);
if ($result is Result::Some {%$json}) { // выводим $json } if ($result is Result::Err {%$httpStatus}) { // выводим $httpStatus } или примерно тоже самое, но с оператором match. Еще пример Есть куча вещей, которые будет удобнее программировать с tagged unions. Например, если кто-то писал парсер, то знает, что первым этапом идет tokenizer (scanner), который разбивает исходный код на токены. Вот тут прямо очень хорошо ложится: есть некий ограниченный набор видов токенов, который можно поместить в enum. Причем некоторые токены, например, строковый литерал или идентификатор, будут содержать еще и значение. В коде будет всё очень удобно и наглядно. Примерно так: enum Token {
case Comma; case LeftBrace; case RightBrace; case StringLiteral(public string $str); case Identifier(public string $identifier); // и т.д. } Что дальше? Неизвестно, примут этот RFC на голосовании или нет, возможно посчитают, что это переусложнит язык и не нужно. Однако тенденция на усиление типизации, а также на перенятие синтаксических "фишек" из других языков налицо. Если примут tagged unions, то я готов поспорить, примут и pattern matching. Если вам интересны подобные статьи про разработку, в частности, что будет дальше с паттерн матчингом, подписывайтесь на телеграм-канал Cross Join! =========== Источник: habr.com =========== Похожие новости:
Разработка веб-сайтов ), #_php, #_programmirovanie ( Программирование ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 17:04
Часовой пояс: UTC + 5