Skip to content

HQL collections

HQL distinguishes membership, positions and lookup through collection contracts and concrete carriers. Their declarations are in std/collections.hql.

Type Intended meaning Design consequence
Collection<T> Finite occurrences with membership and multiplicity No positional order or uniqueness promise
Set<T> Unordered collection of distinct elements No implicit first element or stable iteration order
Seq<T> Positionally ordered sequence, allowing repeated elements Positions are observable; the elements need not be orderable
List<T> A Seq<T> held entirely in memory Length is known; a second traversal is free
Map<K, V> Values associated with distinct keys Lookup is by key; iteration order is not implied

Sets deduplicate using HQL equality, and cards compare by document identity. Maps reject duplicate keys and return Option<V> for lookup. OrderedMap preserves key positions; SortedMap orders those positions by intrinsic key order. See the collection model for the hierarchy and contracts.

Cards are a set

cards : Set<Card>

This is a type statement for the context value, not a proposed standalone declaration syntax. cards represents the current vault or namespace. Sorting can establish a sequence; merely discovering files must not establish a language ordering guarantee. Selecting a reproducible prefix requires a defined order, including how equal sort keys are handled.

cards is inferred as Set<Card>. Sorting it produces List<Card>, which satisfies Seq<Card>, without an explicit conversion:

open = cards | filter(c => c.metadata.status == "todo")
open | sort(by = c => c.title) | map(c => c.title)

A prefix of a set is reproducible when its elements carry their own ordering key — see orderable.

List narrows Seq

type List<T> : Seq<T>

List is not an alias for Seq and not a second name for the same contract. Seq<T> says a position exists for every element — each one can be assigned a natural number — which a lazily produced sequence satisfies without ever being materialized. List<T> adds that the elements are held rather than produced: the collection is in memory, its length is known without consuming it, and traversing it twice costs what traversing it once did. Every List is therefore a Seq, and the narrowing is the usual one.

Seq<T> is an abstract type of law, and the narrowing asserts that List satisfies it — see type-system, Abstract types of law.

Ordered is not orderable

Three words in this area are close enough to be confused, and they are three different things. This is settled, and the register matters as much as the vocabulary.

Concept What it says Whose property
Seq<T> Positional order. A position exists for every element: 0 → 42, 1 → 7, 2 → 19. the collection
Orderable Value order. For any two values of the type, which comes first is determinable — ∀ a, b : T, a ≤ b can be decided. the element type
SortedSeq<T> Both, and they agree. The positional order coincides with the value order. the collection, relative to its elements

The load-bearing sentence:

A sequence is ordered, but its elements need not be orderable.

Seq<Function> is the case that proves it. It has a first, a second and a third element, and no two functions have a meaningful < between them. The positions come from the sequence, not from the values — which is the exact mirror of cards : Set<Card>, where the order comes from the values and not from the collection.

So the phrase "Seq is orderable" is wrong and should not appear. A Seq is ordered, or indexed. Orderable is reserved for a type whose values possess an ordering relation. Sorting expects that relation to be total, or the result is not determined.

Sorting is an operation, not a type property

"Sortable" names something a function can do with a collection, not a foundational property a type has. It is therefore a signature and not a supertype:

fn sort<T>(xs: Collection<T>) : List<T>
where T : Orderable

or, when the caller supplies the relation rather than the element type carrying it:

fn sort<T>(xs: Collection<T>, by: (T, T) -> Ordering) : List<T>

The second form is what makes Seq<Function> sortable without Function being Orderable — the order arrives with the comparator. This is also why [[orderable|Orderable]] stays a supertype rather than becoming a capability: it says the values have a key, and supplying one from outside is the other signature, not the same one narrowed.

Ordering is declared in std/core.hql. SortedSeq<T> remains a design name; sorting currently returns List<T>. A key selector such as by = c => c.title uses the selected key's intrinsic order. Equal keys retain their relative positions in a sequence; unordered inputs have no prior positions to preserve.

Collection functions

Filtering, mapping, sorting and aggregation are typed operations used through pipes or direct calls. Filtering a set preserves set semantics. Mapping returns a list and retains repeated outputs; Set(result) explicitly collapses duplicates. Binding annotations are optional because the checker infers these types from the input and the supplied lambda.

Unordered inputs give an executor room to partition pure work. Sequence order, duplicate behavior and aggregation laws constrain that freedom. A parallel execution strategy must preserve the result promised by the collection function.

See hql/core for the type vocabulary and hql/knowledge for semantic identity.