# Descript v0.2
## Specification
> *This specification is slightly outdated. It was mostly written*
> *before the implementation, and it hasn't been fully updated since.*
> *In particular, injections (primitive types and injected applications)
> *aren't included in the specification (although technically they could
> *be considered input/output records.)*
```descript
A[a: E] | B[b: F] : C
A | B | D => C | D
```
Programs consist of values and reducers.
A value is a union (set) of parts.
A value can't have 2 primitives which are equal, or 2 records which
share the same head.
> Because of the above, a typical implementation represents a value as a
> map of "heads" to "properties", where a primitives is its own head and
> has no properties. This representation is efficient and easy to use,
> because primitives and record heads are treated similarly.
A part is a primitive or a record.
A primitive is a string, number, image, etc..
A record has a (head) symbol and a map of symbols to values (properties -
each entry is a property).
A symbol is an identifier used for reference - symbols can be checked
for equality.
If 2 records have the same head symbol, they belong to the same type,
and they must have the same property keys.
> An implementation can allow any datum to be a symbol. A typical
> implementation restricts a symbol in a record to a literal (is a
> special type of string). Typically some special record, such as
> vectors, can have maps with number keys.
> Usually the symbols in the head of a value are `TitleCamelCase`
> literals, while the symbols in the maps are `lowerCamelCase` literals.
A reducer has an input value and an output value.
An input value is a union of input parts.
An input part is a primitive or input record.
An input record is a symbol (head) and a map of symbols to *optional*
input values (properties).
An input record's head must equal an already-defined record's head.
> Alternatively, an implementation of input records can simply be a
> symbol and a map of symbols to (not optional) input values. Then,
> instead of requiring input records with equal heads to have the same
> property keys, an input record needs to have a subset of the property
> keys of a regular record with the same head.
> An implementation can prevent input values in top-level input records
> from themselves containing input records, and force top-level input
> records to contain non-optional properties.
An output value is a union (set) of output parts.
An output part is a property path, primitive, or output record.
A property path is list of path elements.
A path element is a symbol corresponding to a record's head (head
reference) and another symbol corresponding to a property key in that
record (key reference).
An output record is a symbol (head) and a map of symbols to output
values (properties).
A reducer affects a value if its input value matches the value.
An input value matches a regular value if its parts match the regular
value's parts.
An input primitive matches an equal regular primitive.
An input record matches a regular record if it has the same head (and
thus, the property keys should be equal) and its property values match
the regular value's property values.
A value reduces if there's reducer defined which will affect it. The
value reduces into the reducer's output value applied to the value.
An output value applied to another value is its parts applied to the
other value.
A primitive applied to any value is the primitive itself.
A record applied to a value has the same head and property keys, and the
property values are also applied to that value.
A property path `a<A>b<B` applied to a value is created by this
algorithm.
1. Take the value's parts.
2. Then take from the parts all records with the head `A`.
3. Then look up the entry in their maps with the key `a`.
4. Then take the parts from those values.
5. Then take from those parts all records with the head `B`.
6. Then look up the entry in their maps with the key `b`.
7. Repeat from (2) until the end of the property's path is reached. You
should have a union of parts.
The result of this is the value with those parts.
There can only be one reducer defined for a particular value.
**Implicit Transitive Reducer:** If `ai` reduces to `ao`, then `ai | b`
reduces to `ao | b`, unless another reducer for `ai | b` is defined.
A part can be marked as final.
A value is final if all its parts are final.
Final values can't reduce. If a reducer is defined, an error is raised.
- A value containing a final part *isn't* final, so it has to reduce.
Furthermore, an explicit reducer *can* be defined for it.
All other expressions have to reduce. If no reducer is defined, an error
is raised.
The output of a program is a final value.
A code block contains source code (data) and a language.
Code blocks are usually special - typically a program outputs a code
block which is its compiled form.
> It could be a record or atom, depending on implementation.