Давайте посмотрим, «как скачать страницу из интернета» на Perl 6. Один из удобных способов — воспользоваться модулем HTTP::UserAgent, чей интерфейс очень похож на тот, что был в Perl 5.
Установка модуля с помощью утилиты zef:
$ zef install HTTP::UserAgent
Есть смысл сразу установить поддержку SSL, чтобы иметь возможность ходить на https-адреса:
$ zef install IO::Socket::SSL
Теперь нам доступен весь мир. Пишем программу, которая будет загружать и печать код указанной страницы:
use HTTP::UserAgent;
sub MAIN($url) {
my $ua = HTTP::UserAgent.new;
my $response = $ua.get($url);
say $response.status-line;
say $response.content if $response.is-success;
}
Обратите внимание, что автор модуля использует в именах методов дефисы, а не символы подчеркивания: status-line, is-success.
Сегодня — заключительная часть рассказа о грамматике для разбора даты. В прошлый раз мы добавили класс с действиями, теперь ради упражнения добавим в этот класс атрибуты (то, что в других языках называют данными класса).
Заодно чуть усложним грамматику и научим ее парсить даты, записанные в виде 28.02.18:
Класс действий теперь должен уметь различать ситуации, когда дата записана с полным годом, а когда год представлен только двумя цифрами.
Дату будем хранить в хеше %date, что немного избыточно для этой задачи, но хорошо иллюстрирует, как действовать, когда акции требуют сохранения промежуточных данных.
Здесь действия должны проявить сообразительность, чтобы правильно оценить, к какому столетию относится год.
Теперь самое важное. Поскольку в классе появился атрибут, компилятору потребуется выделить под него место. Для этого от вас требуется создать объект, а не просто передать имя класса:
my $r = DateStr.parse($t, :actions(DateStrActions.new()));
Вчера мы ввели в грамматику блок кода, выполняемый в ответ на совпавшую подстроку. При увеличении сложности исполняемый код и правила грамматики будут сильно перемешиваться визуально и засорять внешний вид, поэтому есть смысл вынести весь код в отдельный класс:
Методы этого класса должны совпадать с названиями правил и токенов в грамматике. Из вчерашнего примера я убрал код из токена TOP грамматики DateStr и поместил его в метод TOP класса DateStrActions.
Теперь необходимо сообщить о действиях перед парсингом:
my $r = DateStr.parse($t, :actions(DateStrActions));
Все остальное остается неизменным. Программа печатает тот же результат:
Мы уже видели, как сделать грамматику для разбора чисел. Но сами по себе грамматики дают лишь ответ, удовлетворяет ли строка заданным правилам. Обычно еще требуется что-то сделать с имеющимися данными. Для этого к грамматике надо добавить действия (actions).
Рассмотрим простейшее действие на примере грамматики для разбора даты.
Когда вы пробуете печатать объект, например: say $x, Perl 6 вызывает метод gist. Этот метод определен для всех встроенных типов — где-то он вызывает метод Str, где-то perl, а где-то формирует особое представление.
Рассмотрим, как можно воспользоваться этим методом, чтобы сделать свой вариант печати объекта:
class X {
has $.value;
method gist {
'[' ~ $!value ~ ']'
}
}
my $x = X.new(value => 42);
say $x; # [42]
$x.say; # [42]
При обращении к say программа печатает число в квадратных скобках: [42].
Обратите внимание, что при интерполяции в строке, заключенной в двойные кавычки, вызывается другой метод — Str:
say $x.Str; # X<140586830040512>
say "$x"; # X<140586830040512>
Если вам требуется кастомная интерполяция, переопределяйте и метод Str:
class X {
has $.value;
method gist {
'[' ~ $!value ~ ']'
}
method Str {
'"' ~ $!value ~ '"'
}
}
my $x = X.new(value => 42);
say $x; # [42]
$x.say; # [42]
say $x.Str; # "42"
say "$x"; # "42"
На этот раз все получилось. Я скачал последние исходники Rakudo Star и действовал по инструкции:
perl Configure.pl --backend=moar --gen-moar
make
make install
Компилировалось все безумно долго, но при этом Raspberry была доступна и могла показать загрузку процессора. В общей сложности процесс занял часа полтора-два, но часть этого времени — на то, чтобы вспомнить, что у меня там что-то компилируется.
На обычном ноутбуке таких цифр вы не увидите, там все компилируется за минуту-две.
Довольно долгим был и процесс после make install. Видимо, если ставить не Rakudo Star, а просто Rakudo, то все пройдет быстрее, потому что для Rakudo Star устанавливаются и тестируются дополнительные модули.
Но тем не менее, хоп-хоп, запускаем (не дожидаясь окончания действий с модулями):
pi@rpi:~/rakudo-star-2018.01 $ ./perl6 -v
This is Rakudo Star version 2018.01 built on MoarVM version 2018.01
implementing Perl 6.c.
Для других ОС
На официальном сайте есть ссылка на гитхаб, где собраны готовые дистрибутивы для многих платформ:
Сегодня мы выйдем за пределы одного чистого программирования и возьмем в руки паяльник. Задача на вечер — помигать светодиодом на Orange Pi.
Orange Pi — это одноплатный мини-компьютер, который, видимо, появился как конкурент Raspberry Pi, при этом и меньше размером, и дешевле. За 15 евро вы получаете четырехядерный компьютер размером со спичечный коробок, куда можно поставить Линукс. Ну не чудо ли? Да еще и c Wi-Fi.
Почти все сказанное ниже применимо, разумеется, и к Raspberry Pi.
С перлом же пришлось повозиться. Я хотел скомпилировать свежий Rakudo Star и начал делать все по инструкции. Началось все замечательно, но потом намертво встало, нагрев процессор до 60-70 градусов. При этом невозможно было достучаться до компьютера по SSH, хотя видно было, что оно просто дико тормозит, но работает.
В итоге я не дождался, пока все соберется, и пошел искать готовые порты. Нашлись два имени — perl6 и rakudo — и это дистрибутив версии 2016.12.
# apt-get install perl6
Конечно, декабрь 2016 это уже очень старое, но при этом версия языка 6.c, что в целом нормально: эта текущая версия спецификации Perl 6.
This is Rakudo version 2016.12 built on MoarVM version 2016.12
implementing Perl 6.c.
Здесь я обращаюсь к внешней утилите gpio (из WiringOP): сначала нужно установить один из портов в режим вывода, а затем поочередно устанавливать его в ноль или единицу.
Обратите внимание на интересные моменты в программе.
Во-первых, бесконечный цикл сделан с помощью ленивой последовательности, каждый элемент которой вычисляется как !*, то есть как отрицание предыдущего. В итоге последовательность состоит из бесконечного чередования True и False.
Во-вторых, булевы величины преобразуются в единицу или ноль с помощью префксного оператора: +$_ и затем подставляются в строку, которая выполняется командной оболочкой.
В-третьих, для запуска используется функция shell. Для этой задачи этого более чем достаточно. В идеале нужно было бы написать код, который напрямую устанавливает биты в соответствующих регистрах устройства.
В-четвертых, не забывайте, что sleep в Perl 6 может принимать и нецелые значения.