Functions

Functions in Teal should work like you expect, and we have already showed various examples.

You can declare nominal function types, like we do for records, to avoid longwinded type declarations, especially when declaring functions that take callbacks. This is done with using function types, and they can be generic as well:

local type Comparator = function<T>(T, T): boolean

local function mysort<A>(arr: {A}, cmp?: Comparator<A>)
   -- ...
end

Note that functions can have optional arguments, as in the cmp? example above. This only affects the arity of the functions (that is, the number of arguments passed to a function), not their types. Note that the question mark is assigned to the argument name, not its type. If an argument is not optional, it may still be given explicitly as nil.

Another thing to know about function declarations is that you can parenthesize the declaration of return types, to avoid ambiguities when using nested declarations and multiple returns:

f: function(function(? string):(number, number), number)

Note also that in this example the string argument of the return function type is optional. When declaring optional arguments in function type declarations which do not use argument names, The question mark is placed ahead of the type. Again, this is an attribute of the argument position, not of the argument type itself.

You can declare functions that generate iterators which can be used in for statements: the function needs to produce another function that iterates. This is an example taken the book "Programming in Lua":

local function allwords(): (function(): string)
   local line = io.read()
   local pos = 1
   return function(): string
      while line do
         local s, e = line:find("%w+", pos)
         if s then
            pos = e + 1
            return line:sub(s, e)
         else
            line = io.read()
            pos = 1
         end
      end
      return nil
   end
end

for word in allwords() do
   print(word)
end

The only changes made to the code above were the addition of type signatures in both function declarations.

Teal also supports macro expressions, which are a restricted form of function whose contents are expanded inline when generating Lua code.

Variadic functions

Just like in Lua, some functions in Teal may receive a variable amount of arguments. Variadic functions can be declared by specifying ... as the last argument of the function:

local function test(...: number)
   print(...)
end

test(1, 2, 3)

In case your function returns a variable amount of values, you may also declare variadic return types by using the type... syntax:

local function test(...: number): number...
   return ...
end

local a, b, c = test(1, 2, 3)

If your function is very dynamic by nature (for example, you are typing a Lua function that can return anything), a typical return type will be any.... When using these functions, often one knows at the call site what are the types of the expected returns, given the arguments that were passed. To set the types of these dynamic returns, you can use the as operator over multiple values, using a parenthesized list of types:

local s = { 1234, "ola" }
local a, b = table.unpack(s) as (number, string)

print(a + 1)      -- `a` has type number
print(b:upper())  -- `b` has type string