Можно ли сделать код во время компиляции не кэшированным в Perl 6? - PullRequest
0 голосов
/ 07 января 2019

Допустим, я хочу создать несколько типов во время компиляции, но перед этим давайте протестируем код во время компиляции на более простом примере:

# in file root.pm6
sub foo($a) { $a.say }

sub EXPORT {
    # Things here may be a lot more complex
    foo 1;
    foo 2;
    foo 1;
    %( one => 1 )
}

и модуль между прямой исходной библиотекой и файлом конечного пользователя:

# in file middle.pm6
use root;
class A {} # Do something with stuff from root.pm6

Файл конечного пользователя:

# in file user.pm6
use middle;

Затем в командной строке:

➜  tester perl6 -I. user.pm6
1
2

Похоже, что третий вызов foo был кэширован и не был выполнен в третий раз.

Такое поведение делает любые относительно сложные вычисления (основанные на повторном использовании кода) в sub EXPORT (как и в других областях времени компиляции) невозможными.

Согласно моему пониманию, код во время компиляции должен выполняться нормально, а его результаты (например, некоторые объявления, настройки и т. Д.) Доступны из скомпилированного модуля другими модулями. Тем не менее, здесь тоже есть какое-то кэширование.

Вопрос, в конечном счете, «Как добиться того, чего я хочу» с возможными вехами:

1) Предназначено ли такое кэширование?

2) Если да, можно ли его отключить, имея преимущества выполнения кода во время компиляции? Если нет, какие еще обходные пути возможны?

ОБНОВЛЕНИЕ 1: более подробно объясняется, что я хочу: во время компиляции я анализирую конфигурационный файл и создаю типы для экспорта. Я хочу, чтобы они были предварительно скомпилированы, вот в чем дело. Типы могут быть вложенными и возможны различные случаи, поэтому я передаю имитацию автомата переходного состояния, реализованную в виде простой подпрограммы с длинным оператором given-where, некоторые ветви рекурсивны (всегда присутствует дно). Проблема, на которой я застрял, заключается в том, что некоторые ветви не будут выполнены после однократного увольнения, что я смог сыграть в простой двойной вызов foo 1, который я представил в основном вопросе.

ОБНОВЛЕНИЕ 2: как упоминалось raiph, оно работает правильно, когда запускается из командной строки, когда уровень косвенности между исходной библиотекой и пользователем-1 равен 0, но когда структура root lib file that creates types -> middleware lib file that patches those -> end-user(be it a test file or another module, не весь код выполняется.

Ответы [ 2 ]

0 голосов
/ 09 января 2019

Кажется, это ошибка Rakudo или что-то достаточно близкое к ней.

По крайней мере, в соответствии с рекомендациями Джонатана Уортингтона, использование note вместо say заставляет пример кода работать по мере необходимости, что очищает все возможные последствия возможного кэширования.

0 голосов
/ 07 января 2019

Может быть, вы смотрите на INIT фазер:

INIT {
    # Things here may be a lot more complex
    foo 1;
    foo 2;
    foo 1;
    %( one => 1 ) 
}

Что может быть слишком многословно для вас:

> use user;
1
2
1
2
1

INIT выполняется во время выполнения . Если вы хотите присвоить значения переменным, он выполнит свою работу.

...