Authoritative source: Values, literals, and basic types

Values, literals, and basic types

tulam is strict by default: an ordinary expression is evaluated as an ordinary value. Literals acquire their precise types from context and standard literal evidence.

Literal families

42
3.14159
'x'
"hello\n"
[1, 2, 3]
{1, True, "three"}
{name = "Ada", age = 36}
<1.0, 2.0, 3.0, 4.0>

These are integer, floating, character, string, list/array, positional tuple, named record, and vector literals. Escapes in characters and strings use the usual quoted representation.

Int, Float64, and the standard string type are defaults only when context does not select another type. An annotation can make the choice explicit:

value count : Int = 42;
value ratio : Float64 = 0.5;

Numeric negation is an operator applied to a number; it is not a separate family of unsigned lexical tokens.

Immutable top-level values

value answer : Int = 42;
value inferred = 40;
value computed : Int = inferred + 2;
value increment : Int -> Int = fn(x:Int) : Int = x + 1;

A value is referenced directly: write computed, not computed(). A value may contain a function, tuple, class object, or any other checked value.

Top-level values are immutable. Mutation is represented explicitly through effects and mutable types; a backend may share, inline, or store a value only when the observable value semantics remain unchanged.

Common basic types

The standard library provides:

Primitive types have no user-visible constructors. Their operations arrive through algebras and target implementations rather than privileged operator rules scattered throughout the language.

Expected types guide literals

function midpoint(x:Float64, y:Float64) : Float64 =
    (x + y) / 2.0;

The parameter and result types give the literals a floating interpretation. In generic code, expected types and literal evidence perform the same job. If the choice remains ambiguous, add a type annotation rather than relying on a backend default.

Equality and display are abstractions

Writing x == y requires coherent Eq evidence for the type. Writing show(x) requires Show evidence. This lets user-defined data participate in the same operations without making every value dynamically comparable or printable.

function same[a:Type](x:a, y:a) : Bool
    requires Eq(a) = x == y;

Pure constants versus effects

An intrinsic value is still a pure constant:

value machineEpsilon : Float64 = intrinsic;

An intrinsic value cannot have an Eff type. Retrieval involving the clock, environment, target, or I/O is an intrinsic function or action, because it is not a timeless immutable value.

Common mistakes

Do not call a value with (), assume every type supports == or show, or use an annotation as if it converted a value. When a literal remains ambiguous, state its intended type explicitly.

Recap

Literals are concise introductions whose types are checked from context. Values are immutable bindings, and capabilities such as equality, display, and numeric operations are selected through typed evidence.

Normative details: Language Reference §3.5 and §7.6.