在下面的代码中,我试图创建一个"函数指针"和函数名称作为通常的变量:
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
),如上例所示?
此外,处理诸如"通常"等变量是没有问题的。变量,例如,将它们作为参数传递给其他函数或将它们包含在类/记录的字段中? (如果它们过于宽泛,请忽略后面这些问题...)如果存在潜在的陷阱(如果有的话),我将不胜感激。
答案 0 :(得分:3)
此代码使用的是一流的函数支持,它是Chapel语言设计中的原型/草稿。您可以在First-class Functions in Chapel技术说明中了解有关原型支持的更多信息。
虽然在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();
答案 1 :(得分:2)
是的,在您的示例中,您使用的是Chapel的initial support for first-class functions。对于第二个问题,您也可以使用function type helper来声明函数数组:
var myfuncs: [1..2] func(int);
这些第一类函数对象可以作为参数传递给函数 - 这就是Futures.async()
的工作方式 - 或存储为记录(Try It Online! example)中的字段。 Chapel的一流功能还包括lambda functions。
要明确的是,这种支持的“初始”方面带有警告(来自文档):
在我们开发并实现更强大的故事之前,应该将此机制视为权宜之计技术,这就是为什么它在本自述文件而不是语言规范中进行描述。