LINUX.ORG.RU

Область видимости для цикла loop в perl6.

 


0

4

Решил попробовать что за зверь такой этот Perl6.

Начал писать циклы и обратил внимание, что на такой момент когда я использую $i в двух разных циклах компилятор ругается на переопределение:

sub test() {
    loop (my Int $i = 0; $i < 10; $i++) { print "$i "}
    print "\n";
    loop (my Int $i = 0; $i < 10; $i++) { 
        print "$i ";
    }
}

test();
Potential difficulties:
    Redeclaration of symbol '$i'
    at C:\Users\batur\work\perl6/.\test.p6:4
    ------>     loop (my Int $i<HERE> = 0; $i < 10; $i++) {
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9

То есть по сути, если я правильно понял, в первом и втором цикле одинаковые $i. Почему так сделали? Почему не сузили область видимости этой переменной до цикла loop, в котором она объявляется? Я вот не могу прикинуть такой use-case, в котором бы от такой области видимости была польза

Тут есть два момента:

1)В Perl 6 области видимости лексические и местами они столь лексические, что это просто непривычно. (кроме случаев, где используется динамическая видимость, тогда нет). Дело в том, что объявление my $i находится внутри фигурных скобок, которые являются телом test. Не внутри какого-то другого, нового блока видимости. Поэтому они доступны в этом блоке, в котором они объявлены, скобки здесь не играют роли. Если задуматься об этом, то это в других языках происходит странность, потому что круглые скобки создают отдельное пространство видимости, которое распространяется на блок, но это вносит некое inconsistency, верно? Perl 6 это очень целостный язык, в нём «специальные случаи, когда правило нарушается» это очень редкие события.

2)loop это довольно редкая конструкция в «реальном» Perl 6, которая нужна, когда ты прям 100% хочешь цикл в стиле С. Это бывает редко. Чаще всего ты хочешь for @source -> .... Если ты хочешь бесконечный цикл, то вместо while True ты пишешь loop {...}. Но если ты хочешь просто итерировать от 1 до 10, делай так:

sub test() { # <- внешний блок открыт здесь
    loop (my $i = 0; #`( нет новых фигурных скобок, всё, что в скобках, это всё ещё внешний блок )
          $i < 10; $i++)
        { #`( вокруг фигурные скобки - это внутренняя область видимости ) }
    for ^10 { say "$_ " }
    say "\n";
    for ^10 -> $i { say "$i " }
}

test();

^10 это сокращение для 0..^10, то есть «от 0 до 10, исключая». 0^..^10 будет от 0 до 10 исключая 0 и 10. Если начало 0, что очень частый случай, то можно сократить.

Lilly ()
Последнее исправление: Lilly (всего исправлений: 1)
Ответ на: комментарий от Lilly

Если у тебя всего один statement(инструкция? Даже не в курсе, как переводят), и это не блок, то можно и поменять местами:

$_.say for ^10;
# или даже
.say for ^10;

^ если ты итерируешь в цикле, и у тебя всего одна переменная «topic», которая $_ (потому что зачем придумывать имя?), то можно её даже, на самом деле, и не указывать, а просто вызывать её методы. И без всяких объявлений волосы будут гладкими и шелковистыми.

Грепнул случаи использования for -> 230 строк в паре проектов, loop -> 20.

Lilly ()
Последнее исправление: Lilly (всего исправлений: 1)
Ответ на: комментарий от WitcherGeralt

Сигнатура - это описание, что можно кинуть в блок кода, арность, имена, типы и всё такое. Это не описание «А вот здесь заделай мне переменную с именем». Параметры и переменные это не одно и то же. Смешивание концепций это не ок.

Lilly ()
Ответ на: комментарий от WitcherGeralt

Вот тут соглашусь. Любое незначительное изменение поведения, которое отличается от того, к которому привык когда-то (важно ли, есть ли под ним основание или нет?) за секунду сводит всё до уровня убожества. Потому что серого нет и есть либо идеальные уберязыки либо убожества. Но идеального нет, поэтому везде одно дерьмо. Поэтому всё так тоскливо.

Lilly ()
Ответ на: комментарий от WitcherGeralt
FANBOY = 'WitcherGeralt' # типа константа
# ...
# ...
# ...
FANBOY = '' # ой

В Python’е даже нормальных констант нет. И вот про это убожество вы тут втирали типа уберязык? Найс.

anonymous ()
Ответ на: комментарий от anonymous

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

Хотя, можно раздуть про смешивание концепций в программировании. Например, смешивание понятий функции и метода, смешивание конструкций loop и for.

Но мне хотелось бы узнать, что ему всё-таки нравится в кодинге, есть ли какие-то штуки, от которых «ого, круто придумано» бывает. WitcherGeralt?

Lilly ()
Ответ на: комментарий от Lilly

Большое спасибо за ответ. Я использовал loop потому что мне нужны индексы. Получается, что область видимости задаётся только фигурными скобками? И ещё сразу спрошу: что значит$_?

snake266 ()
Ответ на: комментарий от snake266

Ещё, как я понял, переменная, которая создаётся в for (->$array-item) иммутабельна, то есть пройтись по массиву и изменить его как то не получиться(ещё одна причина почему я использовал loop). Я поискал в гугле хоть что то по поводу for, но кроме perl6intro ничего интересного не показывает. Есть какие то ссылки или ещё что то по этому поводу

snake266 ()
Ответ на: комментарий от snake266

Получается, что область видимости задаётся только фигурными скобками?

Всё несколько гибче:

1)Переменные, объявленные как «my» имеют лексическую область видимости. Изначально есть MAINLINE, т.е. самый «верх» файла, каждые новые фигурные скобки - новая лексическая область видимости. Из внутреннего блока ты используешь всё из внешних, но переменные должны быть определены до использования.

2)Кроме my есть ещё has (это полезная штука), our, state и несколько других, которые встречаются реже и можно без них, когда начинаешь. Декларатор «has» используется для «метаобъектной» видимости, т.е. это будет атрибут (поле) класса или роли:

class Foo {
    has $!foo; # сигил $, твигил !, это приватный атрибут (нет геттера)
    has $.bar; # твигил '.', это приватный атрибут, у которого есть геттер
    my $.heh;  # классы это, по сути, пакеты, поэтому можно в них делать лексические переменные, по сути это аналог static fields в java или class variables в питоне
    our $.nice; # внутри пакета можно обращаться как $nice, но снаружи можно писать $Foo::nice, потому что our == "наше!"
}

3)С помощью твигила (символ после сигила, чего угодно из четвёрки $@%&)) `*` можно задать динамическую область видимости, которая ищет по тому, кто вызвал кусок кода, а не где именно он находится в файле:

sub a {
    say $*foo;
}


sub b {
    my $*foo = 13;
    a();
}
my $*foo = 42;

a(); # 42, определено выше
b(); # 13, переопределено в b, поиск переменной идёт в пространстве, где блок был вызван, а не определён

что значит `$_`

Специальная переменная, которая задаётся конструкциями, которые задают «контекст». Её имя можно назвать, но если ты делаешь что-то типа `for $fruit in @fruits: $fruit.eat`, то получается переливание из пустого в порожнее, поэтому чтобы меньше печатать, $_ часто достаточно.

Например, контекст цикла, который обходит элементы, это один элемент:

for 1, 2, 3 { say $_; }
# но если хочешь назвать:
for 1, 2, 3 -> $number { say $number }
# контекст конструкции given это то, что было подано в конструкцию:
given 42 {
    when $_ ~~ 42 { say "I was given 42!" }
}

и так далее.

Lilly ()
Ответ на: комментарий от snake266

Смотря как выглядит твоё объявление для массива. Вроде всё мутабельное:

> my @a = 1,2,3;
[1 2 3]
> @a.WHAT
(Array)
> for @a { $_ = 42 }
Nil
> @a
[42 42 42]
> 

Но если ты пишешь что-то типа

my $array = (1, 2, 3);

То это не Array, а List, который действительно иммутабельный.

Касательно документации: лучше docs.perl6.org пока ещё ничего не придумали.

Lilly ()
Ответ на: комментарий от Lilly

Говоря о том, что мне нравится, нельзя говорить только о ЯП, они вторичны, важнее концепции.

Мне действительно нравится Unix way и 17 правил Реймонда. KISS, все дела. Обожаю простые и элегантные решения.

Считаю, что в хорошем языке обязательно должны быть интерфейсы. Они очень классные в Go, там нет необходимости декларировать, что ты их имплементируешь, достаточно им соответствовать. Получается очень гибко и удобно, но плохо читаемо. Довольно прохладно отношусь к ООП, но благодаря перегрузке операторов оно расцветает, люблю перегрузку операторов. Пусть, она и редко действительно нужна, но когда она уместна, это прямо по кайфу. Нравится композиция, нравятся прототипы, декларативщина. Тащусь с декораторов и пропертей как в Python, это метапрограммирование здорового человека, но в основном метапрограммирование меня больше раздражает, ибо это сильно запутывает код. Люблю замыкания, кастовать типы с помощью указателей, структуры. А поразило меня CSP, но поражало очень медленно, ибо я не смог это сходу распробовать. А то как вместе с CSP в Go под капотом везде вшита асинхронщина, это вообще кайф. Ещё мне доставляют switch, for...in и лямбды. Ненавижу async/await и классические для фп встроенные функции. Ещё мне доставляют объекты в JS, на них можно городить и классы, и модули, и вообще всё, что угодно.

WitcherGeralt ★★ ()
Последнее исправление: WitcherGeralt (всего исправлений: 2)
Ответ на: комментарий от WitcherGeralt

Люблю замыкания, кастовать типы с помощью указателей, структуры.

На этом месте текст стал похож на записки маньяка. Не по сути, а по интонации.

anonymous ()
Ответ на: комментарий от WitcherGeralt

Довольно прохладно отношусь к ООП, но благодаря перегрузке операторов оно расцветает, люблю перегрузку операторов

Тут в соседнем треде прям обмазали класс операторами по самое не могу.

Нравится композиция, нравятся прототипы, декларативщина

Для композиции есть роли (прям по Кею и его смоллтолку, правда, там это называется трейтами), декларативщина это годнота.

нет необходимости декларировать, что ты их имплементируешь, достаточно им соответствовать

Я вроде стараюсь следовать лозунгу про пытки разработчиков, но не хотелось бы писать анализ для такого. Как насчёт ситуаций, когда 10 методов реализовал, а в 11-ом опечатка в названии или забыл?

Тащусь с декораторов и пропертей как в Python, это метапрограммирование здорового человека

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

и классические для фп встроенные функции

А их за что? Я понимаю катаморфизмами не всем нравиться запихиваться, но map, grep и друзья это же чудесно.

Lilly ()
Ответ на: комментарий от Lilly

Как насчёт ситуаций, когда 10 методов реализовал, а в 11-ом опечатка в названии или забыл?

Ты же в любом случае в какой-то сигнатуре этот интерфейс будешь использовать, компилятор подстажет тебе, что указанная сущность этот интерфейс не реализует.

А их за что?

Функциональшики любят упороться по вложеноости и лямбдам, там жопа нечитаемая получается. Другое дело list comprehension — все сразу понятно, даже если и не всегда красиво, в Python с их помощью можно даже генераторы фигачить (кстати, люблю генераторы и всякую ленивость). А если их нет, не беда, можно и подлиннее написать, тут разве что reduce незаменима.

WitcherGeralt ★★ ()
Последнее исправление: WitcherGeralt (всего исправлений: 1)
Ответ на: комментарий от anonymous

В Python’е даже нормальных констант нет.

Ты код на одних константах пишешь, что ли? У здоровых людей в константы пишется 1 раз в программе, после лишь читается из них. Делаешь по-другому — ССЗБ.

Virtuos86 ★★★★★ ()
Ответ на: комментарий от WitcherGeralt

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

my $gen = gather { # лениво начинается блок, "gather мне все значения..."
    my $i = 0;
    loop { take $i++ } # каждый take замораживает то, что было при выполнении блока, и отдаёт управление обратно, поддержка continuations как они есть!
}
$_.say for $gen[0..10]; # лениво пишем первые 11 чисел из нашего "генератора"

Ты же в любом случае в какой-то сигнатуре этот интерфейс будешь использовать, компилятор подстажет тебе, что указанная сущность этот интерфейс не реализует.

А, Т.е. указания есть. Хотя, для типизированного да, проще определять. В питоне с утиной типизацией будет похуже, но там и интерфейсов нет как таковых (нет, абстрактные классы это костыль).

Lilly ()
Ответ на: комментарий от vtVitus

Perl6 в продакшене. Ну я грепнул свою директорию с репозиториями cro, что не конечный продукт, а набор библиотек, объединённый общей идеей, но какой-нибудь commaide.com или сам cro.services (это из того, что я сам писал) на нём крутится, так что можно считать «продакшеном». Знаю людей, у которых разные бекенды крутятся на Perl 6, можно поспрашивать core разработчиков, у них понятно, что больше примеров, т.к. они ближе. Другое дело, что много из этого кода проприетарно и из того, что я писал, части принадлежат разным там корпорациям с суровым NDA (можно, конечно, мне не верить, потому что доказать я это не могу, и кто я такой, обычный незнакомец на форуме, который говорит практически «Использования больше, показывать я это не буду»).

В том же Easii (тоже проприетарно, но весьма крупная система для расчёта страхования, приличные объёмы данных, тысячи формул, фронт-бек, вот это вот всё) кода грепать и грепать, но у меня сорцов нет. Грепнул генератор парсера для Comma (2000 строк на Perl 6 генерируют парсер на 70000+ строк Java): 20 for, 1 loop.

А чтобы обходить список с индексами можно так:

my @foo = <foo bar baz>;
# .kv == метод, дающий key-value
for @foo.kv -> $index, $elem { say "$index: $elem" }
Lilly ()
Ответ на: комментарий от Virtuos86

В перл 6 авторы впервые делали нормальный ЯП, а не Perl 5

Но в перле (настоящем) нет таких косяков. С питоном понятно, это детсад. А тут взрослые покурили спайсов и получился ракокот.

bread ()
Ответ на: комментарий от vtVitus

а это плохо, что теперь сорцы можно скрыть через компиляцию.

Неизменяемые «образы» модулей хранятся установленные, так что их можно посмотреть, код там есть. Хотя запускается, конечно, прекомпилированное, поэтому иногда бывает недоразумение, что новички находят эти файлы с кодом и удивляются, когда правки не влияют на запуск. Но это издержки «сделай это быстрым» подхода.

Lilly ()
Ответ на: комментарий от Lilly

Дело в том, что объявление my $i находится внутри фигурных скобок, которые являются телом test. Не внутри какого-то другого, нового блока видимости. Поэтому они доступны в этом блоке, в котором они объявлены, скобки здесь не играют роли.

Тогда нужно запретить my в скобках после loop, иначе получается нежданчик. Даже сами перлисты на этом будут спотыкаться. Аргумент «loop редко нужен» повеселил. Редко но метко можно сесть в лужу.

anonymous ()
Ответ на: комментарий от anonymous

Редко но метко можно сесть в лужу.

Теперь мне очень любопытно, что такого ужасного можно сделать, не зная об этом. Учитывая, что ворнинги вполне показываются. Я думаю, ты сможешь привести пример кода, где эта особенность приводит к ужасному падению в лужу и страшной катастрофе, чтобы подтвердить свои слова, ведь они основаны на реальности, а не «Мне это непривычно значит это плохо». Ведь основаны же?

Lilly ()
Ответ на: комментарий от Lilly

Для протокола уточню, что мне действительно очень интересно, не паясничаю. За несколько лет интенсивного пользования языком для разного, включая разную чёрную магию, я ни разу не обращал на это внимание. За годы в сообществе, отвечания на разные вопросы и чтения разных рассылок я ни разу не видел ни одного упоминания этой штуки и узнал о ней буквально вчера. Сходу я не могу придумать, как это может кого-нибудь усадить в лужу. Типа так:

my $foo = 42;
...
loop (my $foo = $a.start; $a.has-more; $foo = $a.next) { say $foo }
#  вместо
# while $a.has-more {
#     ONCE say $a.start;
#     say $foo.next;
# }
say $foo; # not 42?

И ты видишь ворнинг на старте и думаешь «Хмм, что-то тут не то». Подозреваю, у меня замылен взгляд, и я не могу придумать случай. Буду рад, если откроют глаза.

Lilly ()
Ответ на: комментарий от Lilly

А чтобы обходить список с индексами можно так

За это большое спасибо. Как я понимаю в Perl6 также как и Python разные скобочки обозначают разные виды множеств? Это я про угловые скобки в примере, просто я пока пользовался только []

snake266 ()
Ответ на: комментарий от snake266

Вроде того:

> (1, 2, 3).^name
List
> [1, 2, 3].^name
Array
> <1 2 3>.^name
List
> { answer => 42 }.^name
Hash
> /abc/.^name
Regex
> ('one', 'two').^name
List
> <one two>.^name # если для каждой строки писать три символа `'',` не хочется, то...
List

Когда пишешь в <>, то разделителем является пробел и если что-то похоже на число, то оно парсится как экземпляр класса IntStr или ComplexStr, RatStr, ряд их, в зависимости от формата числа. Объекты IntStr проходят типизацию и для Int и для Str, что... Иногда удобно. Но обычных [] обычно хватает с головой. Есть ещё разные юникодные скобки, но я их никогда не видел и делаю вид, что их нет, полёт хороший.

Самое страшное это то, что есть далеко не один способ создать пару Pair... Вот здесь могут быть вопросы первое время. Сводится к:

> my $p = foo => 42; # покрывает 50% случаев, ключ foo, значение 42
foo => 42
> $p.^name
Pair
> $p = :24hours; # покрывает остальные 50% случаев, ключ hours, значение 24
hours => 24
> $p.^name
Pair
> $p = :hours(24); # покрывает те случаи, которым не хватило 100%
hours => 24
> $p.^name
Pair

Метод ^name это метаметод, возвращающий имя типа чего-либо. WHAT у меня выше используется для того, чтобы получить сам объект типа (ну и там что-нибудь с ним сделать, например записать в переменную или вызвать его конструктор), а не строку имени.

Lilly ()
Ответ на: комментарий от Virtuos86

Ну не знаю, взять тред из-за которого я решил попробовать Perl 6 Perl 6 vs Python 3. Там не так уж и много сообщений, где рассматриваются объективные плюсы и минусы инструментов. В основном, там:«X нинужно юзай это». Ответы Lilly мне запомнились больше всего из этого треда, за их полноту.

А что до проявления себя, можно писать статьи на каком-нибудь хабре. Там и тему можно раскрыть и в коментах на вопросы ответить.

snake266 ()
Ответ на: комментарий от Lilly

Теперь мне очень любопытно, что такого ужасного можно сделать, не зная об этом.

Да очень просто, подумай о вложенных циклах, где кодер влепил ту же i.

anonymous ()
Ответ на: комментарий от snake266

Там не так уж и много сообщений, где рассматриваются объективные плюсы и минусы инструментов. В основном, там:«X нинужно юзай это».

Ненужнисты экономят твое время и силы, а Лиля тебя вербует в секту. Вот в чем разница.

anonymous ()
Ответ на: комментарий от anonymous

Вложенные циклы с одинаково названными переменными?

Такое видел, вложенных циклов с одинаковыми именами не видел. Надеюсь, не увижу в своей жизни, звучит как какой-то особенный приём обфускации из разряда «прищеми себе что-нибудь дверью».

Аргумент принят, но:

for ^3 {
    for ^3 {
        say "Inner: $_";
    }
    say "Outer: $_";
}

^ всё ок.

Lilly ()
Ответ на: комментарий от anonymous

В моем понимании, такие ненужисты хуже п....... (с), так как они говорят что ненужно, но при этом не говорят что нужно. Лучше промолчать со своим «ненужно», а развернуто ответить что не так.

snake266 ()
Ответ на: комментарий от anonymous

Ты забыл дописать, что каждый ненужнист пишет «Используй $langname (который по случайному совпадению использую и я)», что является вербовкой в $langname, просто секты, в которых много приверженцев, работают в более автоматическом режиме за счёт вот этой красоты.

Ужас, мою вербовку раскрыли, но что поделать, в наше время богу крови нужно больше крови! Все хотят больше людей, чтобы заставить их программировать во славу своих маленьких божков. Я отвечаю на вопросы с эгоистичной целью обновлять свои знания (например, про эту фигню с переменными в loop узнал, хотя не знаю, зачем, в соседнем треде узнал кое-что новое про питон). Если это выглядит как свидетельство perl 6, то тут уже ничего не попишешь, для всех хорошим быть не получится, даже если бы я старался.

Lilly ()
Ответ на: комментарий от Lilly

Хорошо, что у вас есть нескучный for, который выглядит еще более обфусцированно, чем вложенные циклы с одинаковыми именами. А в скучном for могут и другие переменные инициализироваться, не только индекс. И вот теперь нужно зорко следить, чтобы имена не перекрывались. Да и в любом случае ворнинги не комильфо, даже если опасности нет.

anonymous ()
Ответ на: комментарий от snake266

они говорят что ненужно, но при этом не говорят что нужно

Дооо, все сказали питон, некоторые даже объяснили почему. И только пара фриков поддержали перл6. Причем заранее ясно, что никаких рациональных причин его выбирать не существует. Одни эмоции.

anonymous ()