Deviations: Functions
Top-arity Functions
Rationale
Top-arity functions represent the "top type" for function of a given arity.
In the Mavis typesystem, the parameters to the function signature
signify "which types may be passed and are guaranteed to not crash the
function. Accordingly, the type-signature any() -> any() represents
a smaller population of functions than the type-signature integer() -> any(),
as the former type signature represents that all values are guaranteed to
succeed, whereas the later represents that only integers are guaranteed to succeed, a less stringent criterion.
Erlang does have a "top type" for functions, namely the any function, which
is denoted in Elixir as... -> any(). However, it is important to note
that there are cases when it is reasonable to be able to select on an
arity-specific top type. See the example below.
Nomenclature
in Mavis, this type is represented as _, _ -> result_type(),
where the number of underscores corresponds to the arity of this function
type.
internally, these functions are represented by placing a positive integer
in the :params field of the Type.Function.t struct.
Example
def my_function(f) when is_function(f, 1) do
:some_result
endshould have signature (_ -> any()) :: :some_result.
note that Dialyzer gives this function the signature (any() -> any()) :: :some_result, which suggests that a lambda passed to my_function must
be able to tolerate any input. In reality, this function will not crash
if passed, for example :erlang.byte_size/1 which has a more restrictive
signature.
A truly any() -> any() lambda would be for example IO.inspect/1.
Notes
At this point, it doesn't seem to qualify the any() -> any() as a fully
qualified "subtype" of the integer() -> any(), though that may be
implemented later.
There is no zero-arity top-arity function.
Normalization to erlang function types
the :params field is replaced by a list of any() types of the appropriate
arity. Namely the following happens:
_ -> any() to any() -> any()
_, _ -> any() to any(), any() -> any()
when performing type inference, any function which is specced to take lambdas
with all any() parameters should be viewed with suspicion and subjected to
inference.