Особенности работы с переменными и литералами в Perl6

Не так давно я решил начать изучать Perl6, даже не смотря на то, что фактически полностью работающего компилятора ещё нету. Подумал что можно смотреть Synopsis'ы, смотреть что из написанного в них уже работает, и изучать как именно это работает на различных примерах. Этим я и начал заниматься, попутно записывая себе в блокнот результаты различных манипуляций с переменными.
И вот в качестве своего первого поста я решил поделиться своими познаниями: тем, что обычно авторы материала оставляют на самостоятельную «проработку» — ответы на вопросы по типу «а что будет если ...» или «а что из себя это представляет в языке».
В этой статье Я опишу какие основные типы данных есть в этом языке и частично затрону вопрос о контекстах — одной из основных особенностей языка Perl.

Виды переменных и типы их возможных значений.
В Perl6 имеется 3 основных вида переменных: Скаляры, Массивы, Хэши.
Для объявления какой либо переменной используется ключевое слово my — объявление локальной переменной, our — для обяъвления глобальной переменной (Это не единственные способы объявления переменных, но пока что хватит).
  • Скаляры.
    Скаляры, это переменные, которые могут содержать единственное значение: Число, строку, булево значение, ссылку.
    Скалярные переменные объявляются с использование знака '$'. Переменные a, b и c объявляются как $a, $b и $c соотвественно. Так же переменные можно сразу же инициализировать значением.
    Например
    my $scalarVar;
    my ($var1, $var2, $var3);
    my $newStr = "Это строка";
    my $bigNumber = 192958238719732641028368452872938741029834612983412038471293847123641892364;
    my ($a, $b, $c) = 1, 2, 3; или my ($a, $b, $c) = (1, 2, 3);
    

    Если переменной при объявлении было присвоено значение одного типа например число, то в любой момент переменной может быть присвоена строка, или любой другой тип данных.
    Например
    my $scalarVar;
    $scalarVar = 'Строка';
    $scalarVar = 25;
    $scalarVar = True;
    

    Основные типы данных:
    • Целые числа.
      Целые числа представляются типом Int(). Если число по количеству разрядов превышает максимальное количество разрядов типа Int() то оно автоматически приводится к типу Num(), которое может без округлений держать целое число любой длины (Я предполагаю что любой длины, так как один раз ради эксперимента я получил число, длиною в 300 тысяч цифр). Для записи слишком больших чисел можно использовать символ '_' для визуального отделения по несколько цифр в числе. Например 1_000_000, 1_0_0_0; 1_00_0, однако лучше последние два варианта не использовать;
    • Дробные числа
      Дробное число представляется типом Rat() или Num() в зависимости от их значения. Числа могут иметь вид 42.01, 10e-5. При присвоении переменной слишком длинных чисел perl6 может округлять дробную часть, но целую часть держит без изменений, какой бы длинной она не была (Опять же я не уверен в этом, но мои эксперименты подсказывают что будет именно так). Если в в результате вычислений получается очень большое дробное число, то результат может быть возвращен как значение Inf, которое является значением типа Num().
    • Строки
      В качестве строки может быть любой набор uncode-символов, ограниченный одинарными кавычками (') или двойными ("). Разница между ними в том, что в первом случае не происходит подстановка переменных а так же спец символов (таких как \n, \t). Если строка записана как 'f ф \n 1' то при выводе все эти символы будут показаны без изменений. Если же написать "f ф \n 1" то на экране окажутся две строки: 'f ф ' и строка ' 1'.
      '\n' Это символ перехода на новую строку.
    • Булево значение
      Это значения True и False (Обязательно с большой буквы!), имеющие тип Bool().
    • Ссылки
      Переменная данного типа указывает на существующий объект. С помощью ссылки можно проводить точно такие же действия как и с самим объектом, на которую она указывает (например обращение к элементу массива).
      Самое главное:
      $a = 10;
      $b = \$a;
      

      В данном случае переменной $b присваивается ссылка на переменную $a. Если вывести на экран значение переменной $b, то по ссылки автоматически будет взято значение переменной $a, НО если переменной $b присвоить новое значение $b=5; то значение 5 будет записано вместо ссылки на переменную $a, а не в саму переменную $a. Т.е. теперь $b будет содержать не ссылку, а просто число.
    • Пара 'Ключ-значение'
      Этот тип имеет имя Pair(). Конструктором пар является '=>'. Например (1=>'a') создает пару, где ключем является 1, а значение по данному ключу — 'a'. Причем возможными значениями ключей являются строки ( в данном случае 1 была автоматически приведена к строковому типу), а значениями по ключу могут быть любые скаляры.

  • Массивы
    В Perl6 массивы динамические, т.е. при их инициализации не нужно указывать максимальный размер, т.к. память выделяется по мере добавления новых элементов. Элементами массива являются любые скаляры и скалярные переменные. В массивах индекс элемента зависит от позиции при объявлении. Конструктором массива является запятая. Например выражение ('a', 502, "str") конструирует массив размером в 3 элемента (круглые скобки не обязательны). Индексы у элементов начинаются с нуля. т.е. нулевым элементом массива является 'a', под индексом 1 находится число 502, под индексом 2 находится «str». Типы скаляров не обязательно должны быть одинаковыми. Для генерации ссылки на массив используются квадратные скобки. Например ['a', 502, "str"] возвращает ссылку на новый массив, которую можно присвоить скалярной переменной.
    Имя массива должно начинаться с символа '@'. Например
    @mass, @colors, @names
    . Причем $names и @names являются разными переменными.
    Массивы могут содержать любое количество элементов различного типа.
    Примеры использования:
    @arr = ('a', 502, "str");
    @arr2 = (10, False, True, $scalarVar);
    

    Для обращения к элементам массива используются квадратные скобки:
    Например выражение @arr2[0] вернет 10, а @arr2[3] вернет не переменную $scalarVar а её значение, которое было на момент создания массива. Чтобы получить значение переменной $scalarVar записывать в массив нужно было ссылку на эту переменную: @arr2 = (10, False, True, \$scalarVar);
    Если изначальный размер массива 2: @arr = (1, 2); и мы хотим задать значение элемента под индексом 5 (Например arr[5] = 'new elem') то массив будет расширен до 6 элементов, а все добавленные элементы кроме arr[5] будут неинициализированы ( Тип этого значения — Any() ).
  • Хэши
    Хэши представляют собой таблицу соотвествий, когда каждому ключу ставится в соотвествии одно значение. Значениями элементов хэша являются любоые скаляры а ключами являются строки.
    Имя хэшей должно начинаться с символа '%':
    my %hash = ('key1'=>'value1', '2'=>200, 'key10'=>True);
    

    Если присвоить хэшу массив, то элементы массива будут попарно составлять элемент хэша:
    my @mas = ('a, 1, 'b', 2);
    my %hash = @mas;
    

    В результате этого в переменной %hash будет храниться ('a'=>1, 'b'=>2);
    Для обращения к элементам хэша используются фигурные скобки:
    %hash{'a'} = 'new value';
    Для добавления нового элемента хэша достаточно просто присвоить значение по новому ключу:
    %hash{'new elem'} = 255;
    Если в качестве ключа использовать число
    %hash{1000} = 20;
    то число конвертируется в строку, поэтому если в хэше уже есть элемент с ключем '1000', то при занесении значения по числовому ключу уже существующее значение перезапишется.
    Так же хэш можно конструировать из пар:
    $a = ('a'=>1);
    $b = ('b'=>2);
    %hash = $a, $b, 'c'=>3;
    



Контексты
Перейдем теперь к контекстам.
Perl 6 контекстно зависимый, это означает, что при различных условиях использования переменной, могут возвращаться различные значения. Прежде всего контекст определяется тем, какой именно переменной будет присваиваться значение:
$a =… — устанавливается скалярный контекст, @a =… устанавливается списочный контекст и т.д.
Имеются следующие контексты:
  • Скалярный контекст
    Скалярный контекст задается с помощью конструкции $(), где внутри скобок указывается выражение, результат которого будет интерпретироваться в скалярном контексте.
    При использовании массивов в скалярном контексте вместо самого массива возвращается ссылка на данный массив, которую уже можно использовать, как имя массива (Например использовать операцию получения элемента массива).
    При использование хэшей в скалярном контексте возвращается ссылка на хэш.
    Более конкретные виды контекстов это:
    • Числовой контекст
      Числовой контекст задается с помощью конструкции +(). Если в результате выражения, интерпретируемого в данном контексте, получается не числовой результат, то будет произведено приведение к числовому типу, и если в результате приведения появится ошибка, то работа скрипта останавливается.
    • Строковый контекст
      Строковый контекст задается с помощью конструкции ~(). Обычно к строковому типу можно привести любое значение, поэтому проблем с данным контекстом не предвидется
    • Логический контекст
      Логический контекст задается с помощью конструкции ?(). Результат выдается по правилам приведения к логическому типу.

  • Списочный контекст
    Списочный контекст задается с помощью конструкции @(). Пример создания массивов:
    @a1 = (1, 2);
    @a2 = (3, 4);
    @a3 = (5, 6);
    

    Однако если написать следующую строку
    @b = (@a1, @a2, @a3);

    то в результате, получится одномерный массив @b, который будет выглядить как (1, 2, 3, 4, 5, 6), а не двумерный массив, выглядящий как ([1, 2], [3, 4], [5, 6]). Получается это из-за того, что списочный контекст «сливает» все переданные ему массивы и хэши в один большой массив. Чтобы получить многомерный массив, необходимо передавать в конструктор не сами массивы, а ссылки на них:
    @b = (\@a1, \@a2, \@a3)

    Если в списочном контексте используется скалярное значение, то в результате получается одноэлементный массив, состоящий из этого скаляра.
    Если в списочном контексте используется хэш, то в массив будут скопированы все ключи и значения из хэша в попарном виде:
    %a = (1=>'a', 2=>'b');
    @a = %a;  # (1, 'a', 2, 'b')
    

    Важно не путать, чем отличается результат выражения (1, 2) от результата выражения [1, 2]:
    в первом случае, получается массив. Если его присвоить скалярной переменной $a = (1, 2) то в итоге в этой переменной будет ссылка на массив, если написать @a = (1, 2) то @a будет массивом из двух элементов.
    Во втором случае, $a = [1, 2] так же будет содержать ссылку на массив, но @a = [1, 2] переменная @a будет массивом, состоящим из одного элемента — ссылки на массив (1, 2), т.к. ссылка является скалярным значением, которое и становится единственным элементом массива @a.
  • Контекст хэша
    В контексте хэша из скалярных переменных можно использовать только пары, или ссылки на массивы и хэши (про массивы ниже).
    Если в контексте хэша используется массив с нечетным количеством элементов, то скрипт останавливает работу, т.к. при конструировании хэша количество ключей и количество значений не будет совпадать.
    Если используется массив с четным количеством элементов, то в итоге получается хэш, в котором ключами являются четные элементы массива (под индексами 0, 2, 4), а значениями являются нечетные элементы массива (под индексами 1, 3, 5)
    Для задания контекста хэша используется конструкция %()
    В случае если написать
    $a = [1, 2];
    %a = $a;
    

    то в результате будет ошибка! — т.к. хэшу присваивается скалярное значение — ссылка, и получается, что количество ключей не соответсвует количеству значений.
    Если же написать:
    $a = [1, 2];
    %a = %($a);
    

    То получается цепочка: ссылка на массив $a используется в хэш-контексте, поэтому берется само значение массива. При приведении типа массива к типу хэша, создается новый хэш (1=>2), и он уже присваивается переменной %a;

Ну вот, на этом мой маленький опыт манипуляций с переменными пока что и ограничивается. Я надеюсь что вы сдесь увидели что-то новое для вас, и интересное. Удачного дня!
Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 8

    0
    было бы намного интереснее, если бы описывалось только, чем perl6 отличается от perl5. Ну или если бы эти отличия хотя бы как-то в тексте выделялись. А то читать и пытаться выловить что-то незнакомое очень напрягает.

    Так что там — типы записывать как Тип(), Bool, Pair(), Any(), явное задание строкового и логического контекста. Что еще?
      0
      Что касается переменных, хотя Я и не описывал это в статье, для получения элемента массива теперь нужно делать так:
      my @arr = (1, 2, 3);
      say @arr[0];
      @arr = (3, 2, 1);
      my %hash = (1=>'a', 2=>'b');
      say %hash{2};
      %hash = ('c'=>3, 'd'=>4);
      

      т.е. теперь нет разницы, к чему идет обращение — к элементу массива или самому массиву — нужно использовать символ '@'. Аналогично с хэшами.
      Так же отличие в том, что теперь по умолчанию переменные обязательно должны быть объявлены с помощью слов my или our или слов из той же группы.
      Ещё одно на мой взгляд главное отличие — это способ хранения чисел в памяти — в пятом перле при присвоении переменной слишком большого целого числа, это число округлялось. В шестом округлений как я понял не происходит.
      Ну и напоследок добавлю, что переменным можно указывать, какие именно типы будут хранится в них
      my Int $number;
      my Str $string;
      

      однако это отличие в данной статье не описывалось. Я как раз собирался второй статьей описать возможность по указанию типов.
      0
      Честно говоря, читая такие статьи (и понимая что в них всё действительно правда, как не сложно в это поверить) — возникает вопрос: зачем столько сил потрачено на perl6? Ну можно там делать

      my %hash = (1=>'a', 2=>'b');
      say %hash{2};

      — так в пятом теперь можно делать

      my $hash = {1=>'a', 2=>'b'};
      say $hash{2};

      и ради этого десять лет пиара? Столько сил угроблено…
        0
        Мне кажется что десять лет хоть и многовато, но в результате получился вполне неплохой (по описанным возможностям) язык — ведь все отличия в одной статье не опишешь.
        Отличия описанные в предидущем комменте это отличия, более менее связанные со статьей, но есть и такие отличия как возможность перегрузки функций, имеющих разные сигнатуры, работа с классами теперь идет без прибегания к bless'у, возможно полноценное наследование, так же то что в функциях могут быть указаны именованные (вроде так называется) аргументы, когда вызов происходит как FuncName(param2=>'value2', param1=>'value1'). Ещё можно сказать о файлах: теперь при открытии файла возвращается его дескриптор, который хранится как скаляр, а не как в пятом перле в ещё одном пространстве имен, и дескриптор представляется в виде объекта.
        Незнаю существенно это или нет, но теперь Perl6 код по подобию Java компилируется в байт код, который потом интерпретируется виртуальной машиной.
        Вобщем отличия есть — некоторые покажутся как косметический ремонт, но есть отличия, которые значительно увеличивают возможности разработчика или облегчают его труд.
          0
          Так дело-то в том, что то что Вы описали как отличия — либо отличиями не является, так как работает так же как и в 5-м перле, либо отличия минимальны. Вот наследование и пространства имён более интересно. Хотя мне кажется, что последние изменения в perl5 превратили его в более-менее приемлемый язык для современного использования.

          Виртуальная машина вообще сама по себе интересна… точнее интересна, если представить себя в 2000-м году. Мне кажется, perl6 вообще был задуман как проект для обучения студентов, без изначальной ориентации на практическое применение. Иначе не объяснить, что столько людей столько времени делали.

          Только что заметил что статья из песочницы. Мог бы — плюсанул бы. Но стоит добавить что-то более интересное.
            0
            Как раз наоборот, Perl6 был задуман как замена пятому, а так же «языком будущего» (не помню только где уже вычитал эту фразу). Однако фразу эту подкрепляли тем, что в язык были добавлены возможности многих уже существующих языков программирования, а так же старались не повторять их ошибок.
            Но про то получит ли шестой перл популярность мы узнаем когда закончат разработку вирт. машины, а про задумку как проект для обучения — про это буду говорить как только получше узнаю, на что способен шестой перл.
            Да кстате, что касается отличий Новый вид регулярных выражений в шестом перле Синтаксис мог конечно с того времени поменяться, однако в синопсах эти грамматики описываются.
              0
              Я имел ввиду, что процесс создания perl6 имеет много учебного значения, но мало практического, а не то, что на нём как на языке программирования будут кого-то учить. То есть кучу удовольствия все получают от процесса создания языка, но не от его использования. И это неудивительно — существующие популярные языки были созданы одним автором, из этого правила, наверно, исключения нет, так что будущее perl6 уже понятно.
                0
                Шестой перл начали разрабатывать с нуля не от скуки. Делали все это для облегчения написания скриптов, т.к. в пятом все конечно работало, но для работы с теми же объектами приходилось совершать лишние телодвижения. В шестом стало побольше удобных синтаксических конструкций, и самое главное, что различные возможности, как то же создание объекта, сделаны не надстройкой над языком, а уже учтены в самом языке.

      Only users with full accounts can post comments. Log in, please.