Function 函数变量和Chapel中的函数数组

Function 函数变量和Chapel中的函数数组,function,chapel,Function,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: [

在下面的代码中,我试图通过将函数名视为常用变量来创建“函数指针”和函数数组:

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() );
这似乎是预期的工作(与教堂1.16版)

所以我想知道函数变量的上述用法是否合法?对于创建函数数组,通常先定义一个具有所需签名的具体函数,然后引用其类型(使用
.type
),如上例所示


此外,将此类变量视为“常用”变量(例如,将其作为参数传递给其他函数或将其作为类/记录的字段包含)是否没有问题?(如果后面的问题过于宽泛,请忽略这些问题…)如果存在潜在的缺陷(如果有的话),我将非常感谢您的建议。

此代码使用了一流的功能支持,这是Chapel语言设计中的原型/草稿。您可以在technote中阅读更多关于原型支持的信息

虽然在1.16及更高版本中使用了许多一流函数,但您可以预期,这一领域的语言设计将被重新审视。特别是,对于是否可以捕获变量的问题,目前还没有一个合理的答案(目前尝试这样做可能会导致一个令人困惑的错误)。不过,我不知道这将在未来的哪个版本中发生变化

关于
myfunc1.type
部分,我在技术说明中提到的“指定一级函数的类型”一节提出了另一种策略。但是,在本例中使用
myfunc1.type
没有任何问题

最后,请注意,当前编译器中的
lambda
支持实际上是通过使用
this
方法创建一个类来运行的。所以你也可以这样做——创建一个“函数对象”(借用C++术语),这有同样的效果。“函数对象”可以是记录或类。如果它是一个类,您可以使用继承来创建一个对象数组,该数组可以根据对象的动态类型响应相同的方法。此策略可能允许您使用一流的函数解决当前的问题。即使完成了第一类函数支持,“函数对象”方法也允许您更明确地了解捕获的变量。特别是,您可以将它们存储为类中的字段,并在类初始值设定项中设置它们。以下是创建和使用不同类型函数对象数组的示例:

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();

是的,在您的示例中,您使用的是Chapel的。对于第二个问题,您也可以使用a来声明函数数组:

var myfuncs: [1..2] func(int);
这些第一类函数对象可以作为参数传递到函数中(这就是工作原理),也可以作为字段存储在记录()中。教堂的一流功能还包括

需要明确的是,此支持的“初始”方面附带了警告(来自文档):

在我们开发并实现一个更健壮的故事之前,这种机制应该被视为一种权宜之计,这就是为什么在本自述文件而不是语言规范中描述它的原因


我帮不上忙,但我也想知道这一点。这绝对是一个很好的观点。除了“表达自由”类型的动机之外,我想,更难的部分将是在NUMA集群范围内的操场上重新分配这种“指向乐趣的指针()”的主要能力,以及最终的表现(从开销严格的阿姆达尔平行度角度来看)——换句话说,在HPC领域实施此类操作的实际成本。(@roygvib在你的个人资料中有一个美好的愿望清单(y))。非常感谢你的详细解释。“一流功能”页面包含许多有用的信息。现在我知道它仍然是一个“beta”(或alpha)特性。因此,正如您所建议的,最好使用类或记录对象(带有方法+参数)并继承它进行自定义。(事实上,这可能比传递一个捕获一些全局参数的函数更简单、更清晰……)我稍后将使用它们。多谢!非常感谢相关页面和TIO示例。这个“func()”正是我想知道的(例如,如何在Chapel中定义签名或原型)。但我有点觉得“func”这个名字可能有点混乱,因为它非常笼统。。。(因此,“functype”或“proctype”等可能是一个更明确的选择?尽管不确定…)我稍后将尝试TIO示例。非常感谢:)
var myfuncs: [1..2] func(int);