muro-lang.dev / docs
Data
In brief: a data declaration is a book entry. Binders before : are parameters. The telescope after : before Type is indices. Constructors must be strictly positive. Nat, Unit, Empty, and ν stay primitive.
A declaration
data Maybe (A : Type) : Type where
nothing : Maybe A
just : A → Maybe A
(examples/maybe.muro.)
- The type former is spec.
- Constructors compute in run and may appear in evidence.
-
There is no kernel constructor named after your type.
Maybe,List,Vec,Finall use the samedty/ctor/mDatarepresentation.
Nat, Unit, Empty, and Stream stay primitive. Do not redeclare them.
Parameters and indices
data Name params : index-telescope Type where
ctor : telescope
Parameters are the binders before :. Indices are the telescope after : and before Type.
data List (A : Type) : Type where -- one parameter, no indices
nil : List A
cons : A → List A → List A
data Fin : Nat → Type where -- no parameters, one index
fzero : Π (n : Nat) → Fin suc(n)
fsuc : Π (n : Nat) → Fin n → Fin suc(n)
Vec has both; see Indexed data.
Match
One named branch per constructor. Explicit motive over the scrutinee (and its indices, when there are indices).
def fromMaybe : run Π (-A : Type) → Π (d : A) → Π (m : Maybe A) → A :=
λ (-A : Type) → λ (d : A) → λ (m : Maybe A) →
match m motive (λ _ → A)
| nothing => d
| just a => a
A is erased. Emit drops that argument. fromMaybe Nat 0 (just (suc 0)) converts to suc 0; fromJust1 is refl.
Positivity
D must not occur left of Π in a constructor telescope.
This is rejected:
data Bad : Type where
mk : Π (n : Nat) → (Bad n → Nat) → Bad n
(Bad is not even well-formed that way — the point is the negative occurrence.)
Recursion
A self-call in run or evidence must use a constructor argument whose type is D …. For lists, that is the tail. For trees, either child.
def length : run Π (- A : Type) → Π (xs : List A) → Nat :=
λ (- A : Type) → λ (xs : List A) →
match xs motive (λ _ → Nat)
| nil => 0
| cons _ as => suc (length A as)
(examples/list.muro. [] is nil; :: is cons.)
def size : run Π (t : Tree) → Nat :=
λ (t : Tree) →
match t motive (λ _ → Nat)
| leaf => 0
| node l r => suc (plus (size l) (size r))
(examples/tree.muro. Both children are smaller.)
When is a data type Data?
+ is allowed only if the type WHNFs to Data. For a user type, every parameter must be Data. Indices are not asked.
-
List Natis Data.+xs : List Natmay be reused. -
List (Nat → Nat)is not. -
Maybe Unitis Data. -
Vec A nis Data iffAis. The indexnis Nat; it does not disqualify the type.
Emit dialect
A 0-argument constructor is an atom: :nil, :nothing, :leaf.
Otherwise a tagged tuple: {:cons, a, as}, {:just, a}, {:node, l, r}.
ones2() is {:cons, {:suc, 0}, {:cons, {:suc, 0}, :nil}}.
{:ok, src} = Muro.emit_file("examples/list.muro", Muro.Lists)
Code.eval_string(src)
Muro.Lists.length(Muro.Lists.ones2())
# {:suc, {:suc, 0}}
Next: Indexed data.
Source on GitHub
· fetched from murolang/muro manual/