Enum polytype::Type

source ·
pub enum Type<N: Name = &'static str> {
    Constructed(N, Vec<Type<N>>),
    Variable(Variable),
}
Expand description

Represents monotypes (fully instantiated, unquantified types).

The primary ways to create a Type are with either the tp! macro or TypeScheme::instantiate. Type::arrow constructs function types (i.e. α → β), as does conversion (Type::from) with Vec and VecDeque for curried arrows.

Variants§

§

Constructed(N, Vec<Type<N>>)

Primitive or composite types (e.g. int, List(α), α → β)

Examples

Primitives have no associated types:

let tint = Type::Constructed("int", vec![]);
assert_eq!(tint.to_string(), "int")

Composites have associated types:

let tint = Type::Constructed("int", vec![]);
let tlist_of_ints = Type::Constructed("list", vec![tint]);
assert_eq!(tlist_of_ints.to_string(), "list(int)");

With the macro:

let t = tp!(list(tp!(int)));
assert_eq!(t.to_string(), "list(int)");

Function types, or “arrows”, are constructed with either Type::arrow, two implementations of Type::from — one for Vec<Type> and one for VecDeque<Type> — or the macro:

let t = Type::arrow(tp!(int), tp!(bool));
assert_eq!(t.to_string(), "int → bool");

let t = Type::from(vec![tp!(int), tp!(int), tp!(bool)]);
assert_eq!(t.to_string(), "int → int → bool");

let t = tp!(@arrow[tp!(int), tp!(int), tp!(bool)]); // prefer this over Type::from
assert_eq!(t.to_string(), "int → int → bool");
§

Variable(Variable)

Type variables (e.g. α, β).

Examples

// any function: α → β
let t = tp!(@arrow[Type::Variable(0), Type::Variable(1)]);
assert_eq!(t.to_string(), "t0 → t1");

With the macro:

// map: (α → β) → [α] → [β]
let t = tp!(@arrow[
    tp!(@arrow[tp!(0), tp!(1)]),
    tp!(list(tp!(0))),
    tp!(list(tp!(1))),
]);
assert_eq!(t.to_string(), "(t0 → t1) → list(t0) → list(t1)");

Implementations§

source§

impl<N: Name> Type<N>

source

pub fn arrow(alpha: Type<N>, beta: Type<N>) -> Type<N>

Construct a function type (i.e. alphabeta).

Examples
let t = Type::arrow(tp!(int), tp!(bool));
assert_eq!(t.to_string(), "int → bool");
source

pub fn as_arrow(&self) -> Option<(&Type<N>, &Type<N>)>

If the type is an arrow, get its associated argument and return types.

Examples
let t = tp!(@arrow[tp!(int), tp!(int), tp!(bool)]);
if let Some((left, right)) = t.as_arrow() {
    assert_eq!(left.to_string(), "int");
    assert_eq!(right.to_string(), "int → bool");
} else { unreachable!() }
source

pub fn args(&self) -> Option<VecDeque<&Type<N>>>

If the type is an arrow, recursively get all curried function arguments.

Examples
let t = tp!(@arrow[tp!(int), tp!(int), tp!(bool)]);
if let Some(args) = t.args() {
    assert_eq!(args.len(), 2);
    assert_eq!(args[0].to_string(), "int");
    assert_eq!(args[1].to_string(), "int");
} else { unreachable!() }
source

pub fn args_destruct(self) -> Option<Vec<Type<N>>>

If the type is an arrow, recursively get all curried function arguments.

source

pub fn returns(&self) -> Option<&Type<N>>

If the type is an arrow, get its ultimate return type.

Examples
let t = tp!(@arrow[tp!(int), tp!(int), tp!(bool)]);
if let Some(ret) = t.returns() {
    assert_eq!(ret.to_string(), "bool");
} else { unreachable!() }
source

pub fn apply(&self, ctx: &Context<N>) -> Type<N>

Applies the type in a Context.

This will substitute type variables for the values associated with them by the context.

Examples
let mut ctx = Context::default();
ctx.unify(&tp!(0), &tp!(int)).expect("unifies");

let t = tp!(list(tp!(0)));
assert_eq!(t.to_string(), "list(t0)");
let t = t.apply(&ctx);
assert_eq!(t.to_string(), "list(int)");
source

pub fn apply_mut(&mut self, ctx: &Context<N>)

Like apply_compress, but works in-place.

source

pub fn generalize(&self, bound: &[Variable]) -> TypeScheme<N>

Generalizes the type by quantifying over free variables in a TypeScheme.

Variables specified by bound remain unquantified.

Examples
let t = tp!(@arrow[tp!(0), tp!(1)]);
assert_eq!(t.to_string(), "t0 → t1");

let mut ctx = Context::default();
ctx.extend(0, tp!(int));

let t_gen = t.apply(&ctx).generalize(&[]);
assert_eq!(t_gen.to_string(), "∀t1. int → t1");

let t_gen = t.apply(&ctx).generalize(&[1]);
assert_eq!(t_gen.to_string(), "int → t1");
source

pub fn vars(&self) -> Vec<Variable>

Compute all the variables present in a type.

Examples
let t = tp!(@arrow[tp!(0), tp!(1)]);
assert_eq!(t.to_string(), "t0 → t1");

let mut vars = t.vars();
vars.sort();
assert_eq!(vars, vec![0, 1]);
source

pub fn substitute(&self, substitution: &HashMap<Variable, Type<N>>) -> Type<N>

Perform a substitution. This is analogous to apply.

Examples
let t = tp!(@arrow[tp!(0), tp!(1)]);
assert_eq!(t.to_string(), "t0 → t1");

let mut substitution = HashMap::new();
substitution.insert(0, tp!(int));
substitution.insert(1, tp!(bool));

let t = t.substitute(&substitution);
assert_eq!(t.to_string(), "int → bool");
source

pub fn substitute_mut(&mut self, substitution: &HashMap<Variable, Type<N>>)

Like substitute, but works in-place.

Trait Implementations§

source§

impl<N: Clone + Name> Clone for Type<N>

source§

fn clone(&self) -> Type<N>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<N: Debug + Name> Debug for Type<N>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<N: Name> Display for Type<N>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
source§

impl<N: Name> From<Vec<Type<N>>> for Type<N>

source§

fn from(tps: Vec<Type<N>>) -> Type<N>

Converts to this type from the input type.
source§

impl<N: Name> From<VecDeque<Type<N>>> for Type<N>

source§

fn from(tps: VecDeque<Type<N>>) -> Type<N>

Converts to this type from the input type.
source§

impl<N: Name> FromStr for Type<N>

source§

fn from_str(s: &str) -> Result<Type<N>, ParseError>

Parse a type from a string. This round-trips with Display. This is a leaky operation and should be avoided wherever possible: names of constructed types will remain until program termination.

Examples
let t_par: Type = "int -> hashmap(str, list(bool))".parse().expect("valid type");
let t_lit = tp!(@arrow[
    tp!(int),
    tp!(hashmap(
        tp!(str),
        tp!(list(tp!(bool))),
    )),
]);
assert_eq!(t_par, t_lit);

let s = "(t1 → t0 → t1) → t1 → list(t0) → t1";
let t: Type<&'static str> = s.parse().expect("valid type");
let round_trip = t.to_string();
assert_eq!(s, round_trip);
§

type Err = ParseError

The associated error which can be returned from parsing.
source§

impl<N: Hash + Name> Hash for Type<N>

source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl<N: PartialEq + Name> PartialEq for Type<N>

source§

fn eq(&self, other: &Type<N>) -> bool

This method tests for self and other values to be equal, and is used by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
source§

impl<N: Eq + Name> Eq for Type<N>

source§

impl<N: Name> StructuralEq for Type<N>

source§

impl<N: Name> StructuralPartialEq for Type<N>

Auto Trait Implementations§

§

impl<N> RefUnwindSafe for Type<N>
where N: RefUnwindSafe,

§

impl<N> Send for Type<N>
where N: Send,

§

impl<N> Sync for Type<N>
where N: Sync,

§

impl<N> Unpin for Type<N>
where N: Unpin,

§

impl<N> UnwindSafe for Type<N>
where N: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T> ToString for T
where T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.