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
end
should 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.