Skip to main content

TypeF

Enum TypeF 

Source
pub enum TypeF<Ty, RRows, ERows, Te> {
Show 15 variants Dyn, Number, Bool, String, Symbol, ForeignId, Contract(Te), Arrow(Ty, Ty), Var(Ident), Forall { var: LocIdent, var_kind: VarKind, body: Ty, }, Enum(ERows), Record(RRows), Dict { type_fields: Ty, flavour: DictTypeFlavour, }, Array(Ty), Wildcard(usize),
}
Expand description

A Nickel type.

§Generic representation (functor)

A Nickel type is represented by a tree and is naturally defined in a recursive manner: for example, one would expect the constructor for function types (Arrow) to look like:

pub enum Type {
     Arrow(Box<Type>, Box<Type>),
     // ...
}

However, TypeF is slightly different, in that it is parametrized by a generic type instead of using a concrete definition like Box<Types> (forget about rows for now):

pub enum TypeF<Ty /* , .. */> {
     Arrow(Ty, Ty),
     // ...
}

Ty is also called a recursive unfolding throughout the documentation. By defining struct Type(TypeF<Box<Types>>), we get back the original, natural definition.

§Motivation 1: variation on Types

Having a generic definition makes it possible to easily create other types with the same shape as Type (seen as trees), but with enriched nodes. The typical use-case in Nickel is the variation on types used by the typechecker. During type inference, the typechecker operates on trees where each node can either be a concrete type, or a unification variable (a unknown type to be inferred). Instead of duplicating the whole definition of Type as well as all basic methods, we can simply have a different recursive definition:


pub enum UnifType {
   UnifVar(VarId),
   Concrete(TypeF<Box<UnifType> /*, .. */>),
   // ..
 }

We get something that looks like normal Nickel types, except that each node can also be a unification variable as well.

§Motivation 2: recursion schemes

This definition is actually in the style of recursion schemes. Pedantically, TypeF (hence the F suffix) is a functor, but the formal details aren’t so important: keep in mind that the F suffix means that the recursive occurrences of subtrees (and enum rows and record rows as well) are replaced by generic parameters.

The usual motivation for recursion schemes is that they allow for elegant and simple definitions of recursive transformation over trees (here, TypeF, and more generally anything with an F suffix) in terms of simple appropriate chaining of map and folding/unfolding operations. A good example is the definition of crate::ast::typ::Type::traverse. Although crate::ast::Node isn’t currently defined using functors per se, the way program transformations are written is in the same style as recursion schemes: we simply define the action of a transformation as a mapping on the current node, and let the traversal take care of the plumbing of recursion and reconstruction.

§Type parameters

  • Ty: the recursive unfolding of Nickel types
  • RRows: the recursive unfolding of record rows
  • ERows: the recursive unfolding of enum rows
  • Te: the type of a term (used to store contracts)

Variants§

§

Dyn

The dynamic type, or unitype. Assigned to values whose actual type is not statically known or checked.

§

Number

A floating point number.

§

Bool

A boolean.

§

String

A string literal.

§

Symbol

A symbol.

See Term::Sealed in nickel_lang_core.

§

ForeignId

The type of Term::ForeignId.

§

Contract(Te)

A type created from a user-defined contract.

§

Arrow(Ty, Ty)

A function.

§

Var(Ident)

A type variable.

§

Forall

A forall binder.

Fields

§var_kind: VarKind
§body: Ty
§

Enum(ERows)

An enum type, composed of a sequence of enum rows.

§

Record(RRows)

A record type, composed of a sequence of record rows.

§

Dict

A dictionary type.

Fields

§type_fields: Ty
§

Array(Ty)

A parametrized array.

§

Wildcard(usize)

A type wildcard, wrapping an ID unique within a given file.

Implementations§

Source§

impl<'ast> TypeF<&'ast Type<'ast>, RecordRows<'ast>, EnumRows<'ast>, &'ast Ast<'ast>>

Source

pub fn spanned(self, pos: TermPos) -> Type<'ast>

Source§

impl<Ty, RRows, ERows, Te> TypeF<Ty, RRows, ERows, Te>

Source

pub fn try_map_state<TyO, RRowsO, ERowsO, TeO, FTy, FRRows, FERows, FTe, S, E>( self, f: FTy, f_rrows: FRRows, f_erows: FERows, f_ctr: FTe, state: &mut S, ) -> Result<TypeF<TyO, RRowsO, ERowsO, TeO>, E>
where FTy: FnMut(Ty, &mut S) -> Result<TyO, E>, FRRows: FnMut(RRows, &mut S) -> Result<RRowsO, E>, FERows: FnMut(ERows, &mut S) -> Result<ERowsO, E>, FTe: FnMut(Te, &mut S) -> Result<TeO, E>,

Map functions over the children nodes of a type, when seen as a tree. The mutable state ( S) is threaded through the calls to the mapped functions. Functions are fallible and may return an error E, which causes try_map_state to return early with the same error.

If we put aside the state and the error (see [RecordRowsF::map), this function makes TypeF a functor (of arity 3). As hinted by the type signature, this function just maps on “one-level” of recursion, so to speak.

Take the instantiated version Type, and a type of the form (Dyn -> Dyn) -> (Number -> Dyn). Then, calling try_map_state(f_ty, ..) on this type rows will map f_ty onto (Dyn -> Dyn) and Number -> Dyn because they are direct children of the root Arrow node.

Note that f_ty isn’t mapped onto Dyn and Number recursively: map isn’t a recursive operation. It’s however a building block to express recursive operations: as an example, see crate::ast::typ::RecordRows::traverse.

Since TypeF may contain record rows and enum rows as well, f_rrows and f_erows are required to know how to map on record and enum types respectively.

Source

pub fn try_map<TyO, RRowsO, ERowsO, TeO, FTy, FRRows, FERows, FTe, E>( self, f: FTy, f_rrows: FRRows, f_erows: FERows, f_ctr: FTe, ) -> Result<TypeF<TyO, RRowsO, ERowsO, TeO>, E>
where FTy: FnMut(Ty) -> Result<TyO, E>, FRRows: FnMut(RRows) -> Result<RRowsO, E>, FERows: FnMut(ERows) -> Result<ERowsO, E>, FTe: FnMut(Te) -> Result<TeO, E>,

Variant of try_map_state without threaded state.

Source

pub fn map_state<TyO, RRowsO, ERowsO, TeO, FTy, FRRows, FERows, FTe, S>( self, f: FTy, f_rrows: FRRows, f_erows: FERows, f_ctr: FTe, state: &mut S, ) -> TypeF<TyO, RRowsO, ERowsO, TeO>
where FTy: FnMut(Ty, &mut S) -> TyO, FRRows: FnMut(RRows, &mut S) -> RRowsO, FERows: FnMut(ERows, &mut S) -> ERowsO, FTe: FnMut(Te, &mut S) -> TeO,

Variant of try_map_state with infallible functions.

Source

pub fn map<TyO, RRowsO, ERowsO, TeO, FTy, FRRows, FERows, FTe>( self, f: FTy, f_rrows: FRRows, f_erows: FERows, f_ctr: FTe, ) -> TypeF<TyO, RRowsO, ERowsO, TeO>
where FTy: FnMut(Ty) -> TyO, FRRows: FnMut(RRows) -> RRowsO, FERows: FnMut(ERows) -> ERowsO, FTe: FnMut(Te) -> TeO,

Variant of try_map_state without threaded state and with infallible functions.

Source

pub fn is_wildcard(&self) -> bool

Source

pub fn is_contract(&self) -> bool

Trait Implementations§

Source§

impl<Ty: Clone, RRows: Clone, ERows: Clone, Te: Clone> Clone for TypeF<Ty, RRows, ERows, Te>

Source§

fn clone(&self) -> TypeF<Ty, RRows, ERows, Te>

Returns a duplicate 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<Ty, RRows, ERows, Te> CloneTo for TypeF<Ty, RRows, ERows, Te>
where Ty: CloneTo, RRows: CloneTo, ERows: CloneTo, Te: CloneTo,

Source§

type Data<'a> = TypeF<<Ty as CloneTo>::Data<'a>, <RRows as CloneTo>::Data<'a>, <ERows as CloneTo>::Data<'a>, <Te as CloneTo>::Data<'a>>

This is always Self, be we need associated types to make Rust understand that Self is always parametric over the 'ast lifetime. We’re using GATs to emulate higher-kinded types.
Source§

fn clone_to<'to>(data: Self::Data<'_>, dest: &'to AstAlloc) -> Self::Data<'to>

Clones owned data from the current allocator to dest.
Source§

impl<Ty: Debug, RRows: Debug, ERows: Debug, Te: Debug> Debug for TypeF<Ty, RRows, ERows, Te>

Source§

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

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

impl<'ast> From<TypeF<&'ast Type<'ast>, RecordRows<'ast>, EnumRows<'ast>, &'ast Ast<'ast>>> for Type<'ast>

Source§

fn from(typ: TypeUnr<'ast>) -> Self

Converts to this type from the input type.
Source§

impl<Ty: PartialEq, RRows: PartialEq, ERows: PartialEq, Te: PartialEq> PartialEq for TypeF<Ty, RRows, ERows, Te>

Source§

fn eq(&self, other: &TypeF<Ty, RRows, ERows, Te>) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

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

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<Ty: Eq, RRows: Eq, ERows: Eq, Te: Eq> Eq for TypeF<Ty, RRows, ERows, Te>

Source§

impl<Ty, RRows, ERows, Te> StructuralPartialEq for TypeF<Ty, RRows, ERows, Te>

Auto Trait Implementations§

§

impl<Ty, RRows, ERows, Te> Freeze for TypeF<Ty, RRows, ERows, Te>
where Te: Freeze, Ty: Freeze, ERows: Freeze, RRows: Freeze,

§

impl<Ty, RRows, ERows, Te> RefUnwindSafe for TypeF<Ty, RRows, ERows, Te>
where Te: RefUnwindSafe, Ty: RefUnwindSafe, ERows: RefUnwindSafe, RRows: RefUnwindSafe,

§

impl<Ty, RRows, ERows, Te> Send for TypeF<Ty, RRows, ERows, Te>
where Te: Send, Ty: Send, ERows: Send, RRows: Send,

§

impl<Ty, RRows, ERows, Te> Sync for TypeF<Ty, RRows, ERows, Te>
where Te: Sync, Ty: Sync, ERows: Sync, RRows: Sync,

§

impl<Ty, RRows, ERows, Te> Unpin for TypeF<Ty, RRows, ERows, Te>
where Te: Unpin, Ty: Unpin, ERows: Unpin, RRows: Unpin,

§

impl<Ty, RRows, ERows, Te> UnsafeUnpin for TypeF<Ty, RRows, ERows, Te>
where Te: UnsafeUnpin, Ty: UnsafeUnpin, ERows: UnsafeUnpin, RRows: UnsafeUnpin,

§

impl<Ty, RRows, ERows, Te> UnwindSafe for TypeF<Ty, RRows, ERows, Te>
where Te: UnwindSafe, Ty: UnwindSafe, ERows: UnwindSafe, RRows: 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
Source§

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

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

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

Source§

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

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

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

Source§

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

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

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

Source§

fn exact_from(value: T) -> U

Source§

impl<T, U> ExactInto<U> for T
where U: ExactFrom<T>,

Source§

fn exact_into(self) -> U

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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T, U> OverflowingInto<U> for T
where U: OverflowingFrom<T>,

Source§

impl<T, U> RoundingInto<U> for T
where U: RoundingFrom<T>,

Source§

impl<T, U> SaturatingInto<U> for T
where U: SaturatingFrom<T>,

Source§

impl<T> ToDebugString for T
where T: Debug,

Source§

fn to_debug_string(&self) -> String

Returns the String produced by Ts Debug implementation.

§Examples
use malachite_base::strings::ToDebugString;

assert_eq!([1, 2, 3].to_debug_string(), "[1, 2, 3]");
assert_eq!(
    [vec![2, 3], vec![], vec![4]].to_debug_string(),
    "[[2, 3], [], [4]]"
);
assert_eq!(Some(5).to_debug_string(), "Some(5)");
Source§

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

Source§

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, U> TryConvert<'_, T> for U
where U: TryFrom<T>,

Source§

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

Source§

fn try_convert( _: &AstAlloc, from: T, ) -> Result<U, <U as TryConvert<'_, T>>::Error>

Source§

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

Source§

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>,

Source§

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.
Source§

impl<T, U> WrappingInto<U> for T
where U: WrappingFrom<T>,

Source§

fn wrapping_into(self) -> U