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:
Bool, withTrueandFalse;Unit, the one-value result used when no payload is interesting;Int,Float64,String, andCharprimitives;- fixed-width integer and floating types;
Maybe(a),Either(a,b),List(a), arrays, and vectors.
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.