Type.Tuple (mavis v0.0.5) View Source
Represents tuple types.
The associated struct has one parameter:
:elements
which may be a list of types, corresponding to the ordered list of tuple element types.
Deviations from standard Erlang/Elixir:
Mavis introduces a new type (that is not expressible via dialyzer).
This is a tuple with minimum arity (n
), this is represented by putting
the tuple {:min, n}
in the :elements
field. The properties of
this type should be self-explanatory. The {:min, 0}
tuple is
equvalent to the standard Erlang type {...}
, aka any tuple
Examples:
the any tuple is
%Type.Tuple{elements: {:min, 0}}
iex> inspect %Type.Tuple{elements: {:min, 0}} "tuple()"
A tuple of minimum size is represented as follows:
iex> inspect %Type.Tuple{elements: {:min, 2}} "tuple({...(min: 2)})"
generic tuples have their types as lists.
iex> inspect %Type.Tuple{elements: [%Type{name: :atom}, %Type{name: :integer}]} "tuple({atom(), integer()})" iex> inspect %Type.Tuple{elements: [:ok, %Type{name: :integer}]} "tuple({:ok, integer()})"
Shortcut Form
The Type
module lets you specify a tuple using "shortcut form" via the
Type.tuple/1
macro:
iex> import Type, only: :macros
iex> tuple {...}
%Type.Tuple{elements: {:min, 0}}
iex> tuple {...(min: 2)}
%Type.Tuple{elements: {:min, 2}}
iex> tuple {:ok, builtin(:integer)}
%Type.Tuple{elements: [:ok, builtin(:integer)]}
Key functions:
comparison
Longer tuples come after shorter tuples; tuples are then ordered using Cartesian dictionary order along the elements list.
iex> import Type, only: :macros
iex> Type.compare(tuple({}), tuple({:foo}))
:lt
iex> Type.compare(tuple({:foo, 1..10}), tuple({:bar, 10..20}))
:gt
intersection
Tuples of different length do not intersect; the intersection is otherwise the Cartesian intersection of the elements.
iex> import Type, only: :macros
iex> Type.intersection(tuple({}), tuple({:ok, builtin(:integer)}))
%Type{name: :none}
iex> Type.intersection(tuple({:ok, builtin(:integer)}), tuple({builtin(:atom), 1..10}))
%Type.Tuple{elements: [:ok, 1..10]}
union
Only tuple types of the same length can be non-trivially unioned, and then, only if one tuple type is a subtype of the other, and they must be identical across all but one dimension.
iex> import Type, only: :macros
iex> Type.union(tuple({:ok, 11..20}), tuple({:ok, 1..10}))
%Type.Tuple{elements: [:ok, 1..20]}
subtype?
A tuple type is the subtype of another if its types are subtypes of the other across all Cartesian dimensions, but is not the subtype of a tuple that requires more minimum values.
iex> import Type, only: :macros
iex> Type.subtype?(tuple({:ok, 1..10}), tuple({builtin(:atom), builtin(:integer)}))
true
iex> Type.subtype?(tuple({:ok, 1..10}), tuple({...(min: 2)}))
true
iex> Type.subtype?(tuple({:ok, 1..10}), tuple({...(min: 3)}))
false
usable_as
A tuple type is usable as another if it each of its elements are usable as the other across all Cartesian dimensions. If any element is disjoint, then it is not usable.
iex> import Type, only: :macros
iex> Type.usable_as(tuple({:ok, 1..10}), tuple({builtin(:atom), builtin(:integer)}))
:ok
iex> Type.usable_as(tuple({:ok, builtin(:integer)}), tuple({builtin(:atom), 1..10}))
{:maybe, [%Type.Message{type: tuple({:ok, builtin(:integer)}),
target: tuple({builtin(:atom), 1..10})}]}
iex> Type.usable_as(tuple({:ok, builtin(:integer)}), tuple({:error, 1..10}))
{:error, %Type.Message{type: tuple({:ok, builtin(:integer)}),
target: tuple({:error, 1..10})}}
Link to this section Summary
Functions
returns the tuple type at the (0-indexed) tuple slot.
a utility function which takes two type lists and ascertains if they can be merged as tuples.
Link to this section Types
Specs
t() :: %Type.Tuple{elements: [Type.t()] | {:min, non_neg_integer()}}
Link to this section Functions
returns the tuple type at the (0-indexed) tuple slot.
iex> import Type, only: :macros
iex> Type.Tuple.elem(tuple({:ok, builtin(:pos_integer)}), 1)
%Type{name: :pos_integer}
a utility function which takes two type lists and ascertains if they can be merged as tuples.
returns the merged list if the two lists are mergeable. This follows from one of two conditions:
- each type in the "narrower" type list is a subtype of the corresponding "broader" type list
- all types are equal except for one
returns nil if the two lists are not mergeable; returns the merged list if the two lists are mergeable.
completes full analysis in a single pass of the function.
Used in common between tuples and function parameters.