fbpx
Wikipedia

Recursive data type

In computer programming languages, a recursive data type (also known as a recursively-defined, inductively-defined or inductive data type) is a data type for values that may contain other values of the same type. Data of recursive types are usually viewed as directed graphs[citation needed].

An important application of recursion in computer science is in defining dynamic data structures such as Lists and Trees. Recursive data structures can dynamically grow to an arbitrarily large size in response to runtime requirements; in contrast, a static array's size requirements must be set at compile time.

Sometimes the term "inductive data type" is used for algebraic data types which are not necessarily recursive.

Example edit

An example is the list type, in Haskell:

data List a = Nil | Cons a (List a) 

This indicates that a list of a's is either an empty list or a cons cell containing an 'a' (the "head" of the list) and another list (the "tail").

Another example is a similar singly linked type in Java:

class List<E> {  E value;  List<E> next; } 

This indicates that non-empty list of type E contains a data member of type E, and a reference to another List object for the rest of the list (or a null reference to indicate that this is the end of the list).

Mutually recursive data types edit

Data types can also be defined by mutual recursion. The most important basic example of this is a tree, which can be defined mutually recursively in terms of a forest (a list of trees). Symbolically:

f: [t[1], ..., t[k]] t: v f 

A forest f consists of a list of trees, while a tree t consists of a pair of a value v and a forest f (its children). This definition is elegant and easy to work with abstractly (such as when proving theorems about properties of trees), as it expresses a tree in simple terms: a list of one type, and a pair of two types.

This mutually recursive definition can be converted to a singly recursive definition by inlining the definition of a forest:

t: v [t[1], ..., t[k]] 

A tree t consists of a pair of a value v and a list of trees (its children). This definition is more compact, but somewhat messier: a tree consists of a pair of one type and a list another, which require disentangling to prove results about.

In Standard ML, the tree and forest data types can be mutually recursively defined as follows, allowing empty trees:[1]

datatype 'a tree = Empty | Node of 'a * 'a forest and 'a forest = Nil | Cons of 'a tree * 'a forest 

In Haskell, the tree and forest data types can be defined similarly:

data Tree a = Empty  | Node (a, Forest a) data Forest a = Nil  | Cons (Tree a) (Forest a) 

Theory edit

In type theory, a recursive type has the general form μα.T where the type variable α may appear in the type T and stands for the entire type itself.

For example, the natural numbers (see Peano arithmetic) may be defined by the Haskell datatype:

data Nat = Zero | Succ Nat 

In type theory, we would say:   where the two arms of the sum type represent the Zero and Succ data constructors. Zero takes no arguments (thus represented by the unit type) and Succ takes another Nat (thus another element of  ).

There are two forms of recursive types: the so-called isorecursive types, and equirecursive types. The two forms differ in how terms of a recursive type are introduced and eliminated.

Isorecursive types edit

With isorecursive types, the recursive type   and its expansion (or unrolling)   (where the notation   indicates that all instances of Z are replaced with Y in X) are distinct (and disjoint) types with special term constructs, usually called roll and unroll, that form an isomorphism between them. To be precise:   and  , and these two are inverse functions.

Equirecursive types edit

Under equirecursive rules, a recursive type   and its unrolling   are equal – that is, those two type expressions are understood to denote the same type. In fact, most theories of equirecursive types go further and essentially specify that any two type expressions with the same "infinite expansion" are equivalent. As a result of these rules, equirecursive types contribute significantly more complexity to a type system than isorecursive types do. Algorithmic problems such as type checking and type inference are more difficult for equirecursive types as well. Since direct comparison does not make sense on an equirecursive type, they can be converted into a canonical form in O(n log n) time, which can easily be compared.[2]

Isorecursive types capture the form of self-referential (or mutually referential) type definitions seen in nominal object-oriented programming languages, and also arise in type-theoretic semantics of objects and classes. In functional programming languages, isorecursive types (in the guise of datatypes) are common too.[3]

Recursive type synonyms edit

In TypeScript, recursion is allowed in type aliases.[4] Thus, the following example is allowed.

type Tree = number | Tree[]; let tree: Tree = [1, [2, 3]]; 

However, recursion is not allowed in type synonyms in Miranda, OCaml (unless -rectypes flag is used or it's a record or variant), or Haskell; so, for example the following Haskell types are illegal:

type Bad = (Int, Bad) type Evil = Bool -> Evil 

Instead, they must be wrapped inside an algebraic data type (even if they only has one constructor):

data Good = Pair Int Good data Fine = Fun (Bool -> Fine) 

This is because type synonyms, like typedefs in C, are replaced with their definition at compile time. (Type synonyms are not "real" types; they are just "aliases" for convenience of the programmer.) But if this is attempted with a recursive type, it will loop infinitely because no matter how many times the alias is substituted, it still refers to itself, e.g. "Bad" will grow indefinitely: Bad(Int, Bad)(Int, (Int, Bad))... .

Another way to see it is that a level of indirection (the algebraic data type) is required to allow the isorecursive type system to figure out when to roll and unroll.

See also edit

References edit

  1. ^ Harper 1998.
  2. ^ "Numbering Matters: First-Order Canonical Forms for Second-Order Recursive Types". CiteSeerX 10.1.1.4.2276.
  3. ^ Revisiting iso-recursive subtyping | Proceedings of the ACM on Programming Languages
  4. ^ (More) Recursive Type Aliases - Announcing TypeScript 3.7 - TypeScript

Sources edit

  • Harper, Robert (1998), , archived from the original on 1999-10-01

recursive, data, type, computer, programming, languages, recursive, data, type, also, known, recursively, defined, inductively, defined, inductive, data, type, data, type, values, that, contain, other, values, same, type, data, recursive, types, usually, viewe. In computer programming languages a recursive data type also known as a recursively defined inductively defined or inductive data type is a data type for values that may contain other values of the same type Data of recursive types are usually viewed as directed graphs citation needed An important application of recursion in computer science is in defining dynamic data structures such as Lists and Trees Recursive data structures can dynamically grow to an arbitrarily large size in response to runtime requirements in contrast a static array s size requirements must be set at compile time Sometimes the term inductive data type is used for algebraic data types which are not necessarily recursive Contents 1 Example 1 1 Mutually recursive data types 2 Theory 2 1 Isorecursive types 2 2 Equirecursive types 3 Recursive type synonyms 4 See also 5 References 6 SourcesExample editSee also Recursion computer science Recursive data structures structural recursion An example is the list type in Haskell data List a Nil Cons a List a This indicates that a list of a s is either an empty list or a cons cell containing an a the head of the list and another list the tail Another example is a similar singly linked type in Java class List lt E gt E value List lt E gt next This indicates that non empty list of type E contains a data member of type E and a reference to another List object for the rest of the list or a null reference to indicate that this is the end of the list Mutually recursive data types edit Further information Mutual recursion Data types Data types can also be defined by mutual recursion The most important basic example of this is a tree which can be defined mutually recursively in terms of a forest a list of trees Symbolically f t 1 t k t v f A forest f consists of a list of trees while a tree t consists of a pair of a value v and a forest f its children This definition is elegant and easy to work with abstractly such as when proving theorems about properties of trees as it expresses a tree in simple terms a list of one type and a pair of two types This mutually recursive definition can be converted to a singly recursive definition by inlining the definition of a forest t v t 1 t k A tree t consists of a pair of a value v and a list of trees its children This definition is more compact but somewhat messier a tree consists of a pair of one type and a list another which require disentangling to prove results about In Standard ML the tree and forest data types can be mutually recursively defined as follows allowing empty trees 1 datatype a tree Empty Node of a a forest and a forest Nil Cons of a tree a forestIn Haskell the tree and forest data types can be defined similarly data Tree a Empty Node a Forest a data Forest a Nil Cons Tree a Forest a Theory editIn type theory a recursive type has the general form ma T where the type variable a may appear in the type T and stands for the entire type itself For example the natural numbers see Peano arithmetic may be defined by the Haskell datatype data Nat Zero Succ Nat In type theory we would say n a t m a 1 a displaystyle nat mu alpha 1 alpha nbsp where the two arms of the sum type represent the Zero and Succ data constructors Zero takes no arguments thus represented by the unit type and Succ takes another Nat thus another element of m a 1 a displaystyle mu alpha 1 alpha nbsp There are two forms of recursive types the so called isorecursive types and equirecursive types The two forms differ in how terms of a recursive type are introduced and eliminated Isorecursive types edit With isorecursive types the recursive type m a T displaystyle mu alpha T nbsp and its expansion or unrolling T m a T a displaystyle T mu alpha T alpha nbsp where the notation X Y Z displaystyle X Y Z nbsp indicates that all instances of Z are replaced with Y in X are distinct and disjoint types with special term constructs usually called roll and unroll that form an isomorphism between them To be precise r o l l T m a T a m a T displaystyle roll T mu alpha T alpha to mu alpha T nbsp and u n r o l l m a T T m a T a displaystyle unroll mu alpha T to T mu alpha T alpha nbsp and these two are inverse functions Equirecursive types edit Under equirecursive rules a recursive type m a T displaystyle mu alpha T nbsp and its unrolling T m a T a displaystyle T mu alpha T alpha nbsp are equal that is those two type expressions are understood to denote the same type In fact most theories of equirecursive types go further and essentially specify that any two type expressions with the same infinite expansion are equivalent As a result of these rules equirecursive types contribute significantly more complexity to a type system than isorecursive types do Algorithmic problems such as type checking and type inference are more difficult for equirecursive types as well Since direct comparison does not make sense on an equirecursive type they can be converted into a canonical form in O n log n time which can easily be compared 2 Isorecursive types capture the form of self referential or mutually referential type definitions seen in nominal object oriented programming languages and also arise in type theoretic semantics of objects and classes In functional programming languages isorecursive types in the guise of datatypes are common too 3 Recursive type synonyms editThis section possibly contains original research Please improve it by verifying the claims made and adding inline citations Statements consisting only of original research should be removed January 2024 Learn how and when to remove this message In TypeScript recursion is allowed in type aliases 4 Thus the following example is allowed type Tree number Tree let tree Tree 1 2 3 However recursion is not allowed in type synonyms in Miranda OCaml unless rectypes flag is used or it s a record or variant or Haskell so for example the following Haskell types are illegal type Bad Int Bad type Evil Bool gt Evil Instead they must be wrapped inside an algebraic data type even if they only has one constructor data Good Pair Int Good data Fine Fun Bool gt Fine This is because type synonyms like typedefs in C are replaced with their definition at compile time Type synonyms are not real types they are just aliases for convenience of the programmer But if this is attempted with a recursive type it will loop infinitely because no matter how many times the alias is substituted it still refers to itself e g Bad will grow indefinitely Bad Int Bad Int Int Bad Another way to see it is that a level of indirection the algebraic data type is required to allow the isorecursive type system to figure out when to roll and unroll See also editRecursive definition Algebraic data type Inductive type Node computer science References edit Harper 1998 Numbering Matters First Order Canonical Forms for Second Order Recursive Types CiteSeerX 10 1 1 4 2276 Revisiting iso recursive subtyping Proceedings of the ACM on Programming Languages More Recursive Type Aliases Announcing TypeScript 3 7 TypeScriptSources editHarper Robert 1998 Datatype Declarations archived from the original on 1999 10 01 Retrieved from https en wikipedia org w index php title Recursive data type amp oldid 1194588413, wikipedia, wiki, book, books, library,

article

, read, download, free, free download, mp3, video, mp4, 3gp, jpg, jpeg, gif, png, picture, music, song, movie, book, game, games.