One type
A mode is a fact about a value. It is not another type argument. Cache(String) and Cache(String) @ global are the same cache.
Deep slots
A bare field or payload follows the value that holds it. Leave the slot alone when that is what you want.
type Pair('a) = {
left: 'a;
right: 'a;
}
Deep Pair
let pairpair: Book.LanguageReference.FieldModes.Pair(String) = Pair { left = "a""a": String; right = "b""b": String; };
expect ✓(pairpair: Book.LanguageReference.FieldModes.Pair(String).leftleft: String, pairpair: Book.LanguageReference.FieldModes.Pair(String).rightright: String) == ("a""a": String, "b""b": String);One slot
@ on a stored slot cuts that axis off the container. Other slots still follow the value. Variant payloads use the same annotation. A function payload needs parentheses, because @ binds tighter than ->. type! opts this variant out of Decode; a function payload has nothing to decode.
type Kept('a) = {
held: 'a @ global;
scratch: 'a;
}
type! Job =
| Now((fn() -> Int) @ spawnable)
| Later { at: String @ global; }
Cut Slots
let keptkept: Book.LanguageReference.FieldModes.Kept(String) = Kept { held = "ada""ada": String; scratch = "note""note": String; };
let jobjob: Book.LanguageReference.FieldModes.Job = NowNow: fn(fn() -> Int) -> Book.LanguageReference.FieldModes.Job(() => 22: Int);
let ranran: Int = match jobjob: Book.LanguageReference.FieldModes.Job {
| Now(runrun: fn() -> Int) -> runrun: fn() -> Int()
| Later { ..; } -> 00: Int
};
expect ✓(keptkept: Book.LanguageReference.FieldModes.Kept(String).heldheld: String, keptkept: Book.LanguageReference.FieldModes.Kept(String).scratchscratch: String, ranran: Int) == ("ada""ada": String, "note""note": String, 22: Int);Every occurrence of a parameter
When every stored 'a shares one cut, write it on the parameter. A slot may repeat that mode. It may not pick a different one. Leave the parameter bare when two slots of 'a differ.
type Cache('a @ global) = {
value: 'a;
}
Parameter Cut
let cachedcached: Book.LanguageReference.FieldModes.Cache(String) = Cache { value = "hello""hello": String; };
✓cachedcached: Book.LanguageReference.FieldModes.Cache(String): Cache(String);
expect ✓cachedcached: Book.LanguageReference.FieldModes.Cache(String).valuevalue: String == "hello""hello": String;Repeating the parameter's mode at a use site is the same type. The annotation does not add a cut the definition does not already have.
Restated Cut
let cachedcached: Book.LanguageReference.FieldModes.Cache(String): Cache(String @ global) = Cache { value = "again""again": String; };
expect ✓cachedcached: Book.LanguageReference.FieldModes.Cache(String).valuevalue: String == "again""again": String;A stored slot takes a concrete mode. A mode variable names a region each call picks, so it belongs on a function's parameters and result.