Relay中具有函数类型的表达式是“可调用的”,这意味着它们可以通过函数调用来调用。 这些由计算结果为闭包的任何表达式(即函数表达式或全局函数)和Relay运算符组成。
调用的语法遵循类似C的语言所使用的语法,如以下示例所示:
let %c = 1;
let %f = fn(%x : Tensor[(), float32], %y : Tensor[(), float32]) { %x + %y + %c };
%f(10, 11)
调用闭包时,在存储环境中评估闭包的主体(即使用自由变量的存储值),并为每个参数添加局部变量绑定; 通过评估主体获得的最终值是调用的返回值。 因此,在上面的示例中,该调用的求值为22。对于操作符,该实现对Relay是不透明的,因此结果留给已注册的TVM实现。注意:文本格式尚不支持类型参数。
类型多态函数还可以在调用站点中包括类型参数。 类型检查时,将类型参数替换为类型参数。 如果函数是类型多态的,并且未提供类型实参,则类型推断将尽可能尝试推断类型实参。 以下代码提供了显式和推断的类型参数的示例:
// %f : fn<a : Type, b : Type, c : Type>(a, b) -> c
let %x1 = %f<Tensor[(), bool], Tensor[(), bool], Tensor[(), bool)]>(True, False);
// %x1 is of type Tensor[(), bool]
let %x2 : () = %f(%x1, %x1)
// the type arguments in the second call are inferred to be <Tensor[(), bool], Tensor[(), bool], ()>
请注意,函数类型中的所有类型关系都必须在每个调用位置都存在。 具体来说,这意味着将根据给定调用站点上参数的特定类型来检查该关系。 这也是多态的一种形式,因为只要满足关系,就可能有多个有效的参数类型和返回类型分配。
例如,如果我们有一个函数%f带有张量参数并具有Broadcast关系,则下面的调用中的参数可能具有满足类型注释的许多不同形状:
let %x : Tensor[(100, 100, 100), float32] = %f(%a, %b);
%x