Функциональная переменная и массив функций в Chapel

В следующем коде я пытаюсь создать «указатель функции» и массив функций, рассматривая имена функций как обычные переменные:

proc myfunc1() { return 100; }
proc myfunc2() { return 200; }

// a function variable?
var myfunc = myfunc1;
writeln( myfunc() );

myfunc = myfunc2;
writeln( myfunc() );

// an array of functions?
var myfuncs: [1..2] myfunc1.type;

writeln( myfuncs.type: string );

myfuncs[ 1 ] = myfunc1;
myfuncs[ 2 ] = myfunc2;

for fun in myfuncs do
    writeln( fun() );

который, кажется, работает как положено (с Chapel v1.16)

100
200
[domain(1,int(64),false)] chpl__fcf_type_void_int64_t
100
200

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

Кроме того, не проблема ли рассматривать такие переменные как «обычные» переменные, например, передавать их другим функциям в качестве аргументов или включать их как поле класса/записи? (Пожалуйста, игнорируйте эти последние вопросы, если они слишком широки...) Я был бы признателен за любые советы, если есть потенциальные ловушки (если таковые имеются).


person roygvib    schedule 21.02.2018    source источник
comment
Я не могу помочь, но я тоже хочу знать это.   -  person Brian Dolan    schedule 21.02.2018
comment
Определенно хороший момент. Помимо мотивации типа свободы выражения мне кажется, что более сложной частью будет принципиальная возможность перераспределения такого указателя-на-Fun() на игровые площадки всего кластера NUMA и то, что будет конечная производительность (рассматриваемая с точки зрения строгого параллелизма Амдала) — другими словами, фактические затраты на включение такого метода работы в области высокопроизводительных вычислений. ( @roygvib хороший список пожеланий в вашем профиле (y) ).   -  person user3666197    schedule 21.02.2018


Ответы (2)


Этот код использует поддержку функций первого класса, которая является прототипом/черновиком в дизайне языка Chapel. Подробнее о поддержке прототипов можно прочитать в разделе Первоклассные функции в Chapel техническое примечание.

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

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

Наконец, обратите внимание, что поддержка lambda в текущем компиляторе фактически работает путем создания класса с методом this. Таким образом, вы можете сделать то же самое - создать "объект функции" (если заимствовать термин С++) - это будет иметь тот же эффект. «Функциональный объект» может быть записью или классом. Если это класс, вы можете использовать наследование, чтобы создать массив объектов, которые могут реагировать на один и тот же метод в зависимости от их динамического типа. Эта стратегия может позволить вам обойти текущие проблемы с функциями первого класса. Даже если поддержка первоклассных функций завершена, подход «объект-функция» позволяет вам более явно указывать захваченные переменные. В частности, вы можете сохранить их как поля в классе и установить их в инициализаторе класса. Вот пример создания и использования массива различных типов объектов-функций:

class BaseHandler {
  // consider these as "pure virtual" functions
  proc name():string { halt("base name called"); }
  proc this(arg:int) { halt("base greet called"); }
}
class HelloHandler : BaseHandler {
  proc name():string { return "hello"; }
  proc this(arg:int) { writeln("Hello ", arg); }
}
class CiaoHandler : BaseHandler {
  proc name():string { return "ciao"; }
  proc this(arg:int) { writeln("Ciao ", arg); }
}

proc test() {
  // create an array of handlers
  var handlers:[1..0] BaseHandler;
  handlers.push_back(new HelloHandler());
  handlers.push_back(new CiaoHandler());

  for h in handlers {
    h(1); // calls 'this' method in instance
  }
}

test();
person mppf    schedule 21.02.2018
comment
Большое спасибо за подробное объяснение. Первоклассная страница функций содержит много полезной информации. Теперь я понимаю, что это все еще бета (или альфа) функция. Итак, как вы предложили, может быть лучше использовать класс или объект записи (с методами + параметрами) и наследовать его для настройки. (В самом деле, это может быть проще и понятнее, чем передача функции, которая фиксирует какие-то глобальные параметры...) Я поиграюсь с ними позже. Спасибо большое! - person roygvib; 22.02.2018

Да, в вашем примере вы используете поддержку initial Chapel. для первоклассных функций. На ваш второй вопрос вы можете в качестве альтернативы использовать помощник типа функции для объявления массива функций:

var myfuncs: [1..2] func(int);

Эти первоклассные функциональные объекты могут быть переданы в качестве аргументов в функции следующим образом: Futures.async() works or stored as fields in a record (Попробуйте онлайн! пример). Первоклассные функциональные возможности Chapel также включают лямбда-функции. .

Чтобы было ясно, «начальный» аспект этой поддержки поставляется с оговоркой (из документации):

Этот механизм следует рассматривать как временную технологию, пока мы не разработаем и не внедрим более надежную историю, поэтому он описан в этом README, а не в спецификации языка.

person Nick    schedule 21.02.2018
comment
Большое спасибо за соответствующие страницы и пример TIO. Эта функция func() — это именно то, о чем я думал (т. е. как определить подпись или прототип в Chapel). Но я немного чувствую, что имя func может немного сбивать с толку, потому что оно очень общее... (поэтому functype или proctype и т. д. могут быть более понятной альтернативой? хотя не уверен...) Я попробую пример TIO позже. Спасибо большое :) - person roygvib; 22.02.2018