Skip to content
heff

Numbers

Types

TypeWhat it is
Intan integer of any size
Float64an IEEE 754 double
Int8 Int16 Int32 Int64fixed-width integers, two’s complement
UInt8 UInt16 UInt32 UInt64fixed-width unsigned integers
Float32an IEEE 754 single

Literals

import uint8 as UInt8
-- | >>> debug mask
-- | "240"
mask : UInt8
mask = 0xf0
million : Int
million = 1_000_000
flags : Int
flags = 0b1010
mode : Int
mode = 0o644
  • An integer literal can be of any number type; a fractional one, 2.5, of a float type. A fractional literal may have an exponent after its digits, 6.02e23, 1.5e-3; a point comes first, 1.0e23, not 1e23. It is the float of its type nearest the decimal it writes, rounded once: (1.0000000596046448 : Float32) is the Float32 above 1, not 1.0, as it would be rounded to a Float64 first. Below half the least float of its type it is 0.0; beyond the greatest, an error, as is any literal that does not fit its type.
  • debug writes a float as such a literal, the fewest digits that read back as it: debug 1.0e23 is "1.0e23", debug (neg 0.0) is "-0.0".
  • parseFloat s reads such a decimal back, at run time, as a literal is read: parseFloat "0.1" is Just 0.1, and float32’s parseFloat32 the Float32 nearest it, rounded once. A -, digits, a point and digits, an exponent (2.5, -1e-7, 12.5E+3); anything else ("Infinity", "1.", " 1") is Nothing.
  • Hexadecimal 0x605, octal 0o644 and binary 0b1010 are allowed, and _ can separate digits.
  • The literal must fit its type: 300 as a UInt8 is an error, and so is 1.5 as an Int32.
  • Where nothing decides the type, an integer literal is an Int and a fractional one a Float64. In [1, 2.5], both are Float64.

Negative literals

A - right before a digit is the literal’s sign, unless it comes right after an operand with no space. So:

WrittenMeans
a - 1, a-1subtraction
f -1f applied to -1
-128 as an Int8its least value

A - right before a name or ( negates it: -p.x, -(f y). It is the neg in scope, so it works for any type with a Negation. f -x is f (-x); - x, with a space, is not a negation.

Operations

Numbers are added, compared and divided by the prelude’s operators, whose theories each number type has: see Operators. How each type divides, rounds and wraps around is with its instances:

A fixed-width type’s module is imported by a name, as they share their names (import int64 as Int64), and brings in its instances, so the prelude’s operators work at its type. One fixed-width type goes to another by way of an Int:

import int32 as Int32
import int8 as Int8
narrow : Int32 -> Int8
narrow x = Int8.fromInt (Int32.toInt x)

How each backend stores numbers is in Providers.