- A data structure or structures (often called the sorts)
- A set of operations (called the methods or operations).
- A precise description of the types of the methods (called a signature).
- A precise set of rules about how it behaves (called the abstract specification or the axiomatic description).
- An implementation hidden from the programmer who uses the data type.

An example

- A list based table mechanism.
- Constant time addition
- Linear time search

- A balanced tree based table mechanism
- Log time addition
- Log time search

In Haskell two features of the language are commonly used to implement abstract data types.

- The class system
- The module system

Features of Algebraic Data Types

- Defined using "data" declartion in Haskell.
- Exposes the Constructors of the internal representation.
- Data is decomposed using pattern matching.
- Makes the programmers responsible for maintaining implementation invariants.
- Has only a single implementation.
- All internals of the implementation are visible to programmers who use the type.

Features of Abstract Data Types

- Implemented with the class system or module system in Haskell.
- Internal implementation details hidden from user. Constructors are hidden and no pattern matching is available.
- Access to data type is through "methods" or "operators"
- The exact types of the "methods" or operators is exposed in a
**signature**. - Supports multiple implementations.
- Operational semantics is described by an axiomatic specification. All actual implementations must meet the specification (behave correctly) but are free to choose any implementation.

- A data type or types
- A set of operations
- A specification
- A signature
- A set of axioms
- A set of implementation

A Signature is a set of contracts (or types) that the operation of the abstract data type must export (i.e. provide implementations for). In some systems the signature also includes axioms that all implementations must obey.

Examples

- Stack
push :: a -> Stack a -> Stack a top :: Stack a -> a pop :: Stack a -> Stack a emptyStack:: Stack a empty :: Stack a -> Bool

- Queue
enQ :: a -> Queue a -> Queue a deQ :: Queue a -> (a,Queue q) emptyQ :: Queue a isEmpty:: Queue a -> Bool

- Priority Queue
add :: a -> PQ a -> PQ a min :: PQ a -> Maybe(a) deletemin:: PQ a -> Maybe(PQ a) emptyPQ :: PQ a -> Bool

- Numbers
(+):: Num t => t -> t -> t (*):: Num t => t -> t -> t 0:: Num t -> t

etc.

Implementing using the class system is done through class and instance declarations.

class Stacklike t where push :: a -> t a -> t a top :: t a -> a pop :: t a -> t a emptyStack:: t a empty :: t a -> Bool |

instance Stacklike [] where push x xs = x :xs top (x:xs) = x pop (x:xs) = xs emptyStack = [] empty [] = True empty (x:xs) = False |

Implementing using the module system is done through manipulating what information is exported from a file.

module Stack(Stack(),push,top,pop,emptyStack,empty) where data Stack a = EmptyStack | Push a (Stack a) push :: a -> Stack a -> Stack a push x xs = Push x xs top :: Stack a -> a top (Push x xs) = x pop :: Stack a -> Stack a pop (Push x xs) = xs emptyStack:: Stack a emptyStack = EmptyStack empty :: Stack a -> Bool empty = EmptyStack |

An algebraic specification describes how an implementation should behave. It is generally written as a set of equivalencies. I.e. equations that state that two programs are equal. Normally equality between programs is described in terms of observational equivalence.

Two programs are observational equivalent if there are no program contexts that can distinguish them. A context is an additional set of commands or expressions surrounding the programs.

In terms of abstract data types contexts are often described as a series of calls to the operations or methods of the abstract type.

- In a pure implementation, observational equivalence means two program fragments can be switched for one another and no program could tell the difference.
- In a command based implementation, observational equivalence usually means that the sequence of updates to variables is such that for any starting set of values of the variables, the end set of values is the same.

Some example axiomatic specifications follow:

- For stacks
pop(push a s) == s top(push a s) == a not((push a s) == emptyStack)

- For Queues
fst(deQ(enQ a emptyQ)) == a deQ(enQ a (enQ b q)) == deQ(enQ b q)