Привязка скаляра к переменной без сигилла (Perl 6)

Позвольте мне начать с того, что я понимаю, что то, о чем я спрашиваю в названии, является сомнительной практикой (как объяснено здесь), но мое непонимание касается синтаксиса.

Когда я впервые попытался связать скаляр с символом без знака, я сделал это:

my \a = $(3);

думая, что $(...) упакует Int 3 в скаляр (как это предлагается в документации), который затем будет связан с символом a. Это, похоже, не работает: скаляр нигде не найти (a.VAR.WHAT возвращает (Int), а не (Scalar)).

В вышеупомянутой публикации raiph упоминает, что желаемое связывание может быть выполнено с использованием другого синтаксиса:

my \a = $ = 3;

который работает. Учитывая результат, я подозреваю, что утверждение можно сформулировать эквивалентно, хотя и менее кратко, как: my \a = (my $ = 3)что я мог тогда понять.

Это оставляет вопрос: почему попытка $(...) не работает, и что он делает вместо этого?

2 ответа

Решение

Какие $(…) делает это превратить значение в item,
(Значение в скалярной переменной ($a) также помечается как элемент)

say flat (1,2,      (3,4)  );
# (1 2 3 4)

say flat (1,2,    $((3,4)) );
# (1 2 (3 4))

say flat (1,2, item((3,4)) );
# (1 2 (3 4))

По сути, это предотвращает сглаживание значения. Причина его существования заключается в том, что Perl 6 не сглаживает списки так сильно, как большинство других языков, и иногда вам нужно немного больше контролировать выравнивание.


Следующий только вид делает то, что вы хотите, чтобы он делал

my \a = $ = 3;

Голый $ является анонимным state переменная.

my \a = (state $) = 3;

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

sub foo ( $init ) {
  my \a = $ = $init; # my \a = (state $) = $init;

  (^10).map: {
    sleep 0.1;
    ++a
  }
}

.say for await (start foo(0)), (start foo(42));
# (43 44 45 46 47 48 49 50 51 52)
# (53 54 55 56 57 58 59 60 61 62)

# If foo(42) beat out foo(0) instead it would result in:
# (1 2 3 4 5 6 7 8 9 10)
# (11 12 13 14 15 16 17 18 19 20)

Обратите внимание, что переменная является общей для вызовов.
Первое обещание останавливается на sleep вызов, а затем второй устанавливает переменную состояния до первого запуска ++a,

Если вы используете my $ вместо этого теперь он работает правильно.

sub foo ( $init ) {
  my \a = my $ = $init;

  (^10).map: {
    sleep 0.1;
    ++a
  }
}

.say for await (start foo(0)), (start foo(42));
# (1 2 3 4 5 6 7 8 9 10)
# (43 44 45 46 47 48 49 50 51 52)

Дело в том, что сигиллярные "переменные" на самом деле не являются переменными (они не меняются), они больше похожи на лексически ограниченные (не) константы.

constant \foo = (1..10).pick; # only pick one value and never change it

say foo;
for ^5 {
  my \foo = (1..10).pick;     # pick a new one each time through

  say foo;
}

По сути, весь их смысл в том, чтобы быть как можно ближе к значению, которое вы ему присваиваете. (Статическое одиночное назначение)

# these work basically the same
-> \a        {…}
-> \a is raw {…}
-> $a is raw {…}

# as do these
my \a  = $i;
my \a := $i;
my $a := $i;

Обратите внимание, что выше я написал следующее:

my \a = (state $) = 3;

Обычно в объявлении состояния var присваивание происходит только при первом запуске кода. голый $ не имеет декларации как таковой, поэтому я должен был предотвратить такое поведение, поместив декларацию в скобках.

# bare $
for (5 ... 1) {
  my \a =        $  = $_; # set each time through the loop

  say a *= 2; # 15 12 9 6 3
}

# state in parens
for (5 ... 1) {
  my \a = (state $) = $_; # set each time through the loop

  say a *= 2; # 15 12 9 6 3
}

# normal state declaration
for (5 ... 1) {
  my \a =  state $  = $_; # set it only on the first time through the loop

  say a *= 2; # 15 45 135 405 1215
}

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

my \a = $(3); 
say a.WHAT; # OUTPUT: «(Int)␤»
say a.VAR.WHAT; # OUTPUT: «(Int)␤»

Здесь, делая $(3), вы фактически помещаете в скалярный контекст то, что уже находится в скалярном контексте:

my \a = 3; say a.WHAT; say a.VAR.WHAT; # OUTPUT: «(Int)␤(Int)␤»

Однако вторая форма в вашем вопросе делает что-то другое. Вы привязываетесь к анонимной переменной, которая является контейнером:

my \a = $ = 3; 
say a.WHAT;    # OUTPUT: «(Int)␤»
say a.VAR.WHAT;# OUTPUT: «(Scalar)␤»

В первом случае a был псевдоним для 3 (или $(3), что то же самое); во-вторых, a это псевдоним для $, который является контейнером, чье значение 3, Этот последний случай эквивалентен:

 my $anon = 3; say $anon.WHAT; say $anon.VAR.WHAT; # OUTPUT: «(Int)␤(Scalar)␤»

(Если у вас есть предложения по улучшению документации, я буду рад ее рассмотреть)

Другие вопросы по тегам