kex docs Standard Library

NumberFormat

type Integer

Implements Monoid, Group, Blankable, Truthyable.

Whole numbers, of arbitrary size.

Integer has no width limit: factorials and cryptographic moduli are ordinary values, not a special big-number type you have to opt into.

Integer and Float are one numeric tower: they compare and order across the boundary, so 0 == 0.0 is true and [1, 2.5, 3].sort works. What differs is the arithmetic. / on two integers is integer division, and sqrt answers a Float because a square root generally is one.

7 / 2          # => 3      (integer division)
7.0 / 2.0      # => 3.5
16.sqrt        # => 4.0    (a Float, even from an Integer)
(-7).modulo(3) # => 2      (mathematical modulo, not C remainder)

even?

even? : Bool

Returns true when the integer is divisible by two. Zero is even, and negative numbers follow the same rule.

Returns true for an even integer

Examples
4.even?      # => true
3.even?      # => false
(-2).even?   # => true

Splitting a list into evens and odds

[1, 2, 3, 4].partition { |n| n.even? }   # => ([2, 4], [1, 3])

odd?

odd? : Bool

Returns true when the integer is not divisible by two. The opposite of even?.

Returns true for an odd integer

Examples
3.odd?   # => true
4.odd?   # => false

abs

abs : Integer

Returns the magnitude of the integer, discarding its sign.

Returns the absolute value

Examples
(-5).abs   # => 5
5.abs      # => 5

Distance between two positions

(a - b).abs

sqrt

sqrt : Float

Returns the square root as a Float.

The result is a Float even when the root is exact, because in general it is not. Round or floor it when you need an integer back.

Returns the square root

Examples
16.sqrt          # => 4.0
2.sqrt           # => 1.4142135623730951
16.sqrt.round    # => 4

modulo

modulo(n: Integer) -> Integer

Returns this modulo n.

The result takes the sign of n, which is mathematical modulo rather than the C-style remainder other languages give. That is what makes it safe for wrapping an index that may have gone negative.

Parameters
n
the modulus

Returns the remainder, with the sign of n

Examples
7.modulo(3)      # => 1
(-7).modulo(3)   # => 2

Wrapping an index around a list

let items = ["a", "b", "c"]
items.at((-1).modulo(items.count))   # => Just("c")

in?

in?(range: Range<Integer>) -> Bool

Returns true when the integer falls inside range, endpoints included.

Parameters
range
the inclusive range

Returns true when the integer is in range

Examples
5.in?(1..10)    # => true
11.in?(1..10)   # => false

Validating a port number

port.in?(1..65535)

times

times(block: (Integer -> Void)) -> Void
times(block: Block<Void>) -> Void

Calls f exactly this times, passing the 0-based iteration index.

This is the counting loop. When you want the numbers themselves rather than a count of repetitions, (1..n).items.each often reads better.

Parameters
f
called once per iteration with the index
Examples
3.times { |i| IO.printLine(i) }   # prints 0, then 1, then 2

Repeating an action

retries.times { |_| attemptConnection }

Repeating an action that needs no index

3.times do
  IO.printLine("hi")
end

floor

floor : Integer

Returns the integer unchanged. Present so that code written against Number works whichever half of the tower it is handed.

Returns the same integer

Examples
7.floor   # => 7

ceil

ceil : Integer

Returns the integer unchanged. The Integer counterpart of Float.ceil.

Returns the same integer

Examples
7.ceil   # => 7

round

round : Integer

Returns the integer unchanged. The Integer counterpart of Float.round.

Returns the same integer

Examples
7.round   # => 7

From Monoid

repeat
Combines this value with itself n times.

Defined in other modules

type Float

Implements Blankable, Truthyable.

Double-precision floating-point numbers.

A Kex Float is always finite. An operation that would produce NaN or Infinity raises instead: the same rule the BEAM enforces, where those two values cannot exist at all. So a Float you are holding is always a real number, and there is no nan? to check for.

Float and Integer compare and order across the boundary; see Integer for the rest of the numeric tower.

3.7.floor      # => 3
3.7.round      # => 4
(-3.7).toInteger  # => -3   (truncates toward zero)

abs

abs : Float

Returns the magnitude of the float, discarding its sign.

Returns the absolute value

Examples
(-3.14).abs   # => 3.14
3.14.abs      # => 3.14

An approximate-equality test

(a - b).abs < 0.0001

sqrt

sqrt : Float

Returns the square root. Raises for a negative receiver, which has no real root.

Returns the square root

Examples
25.0.sqrt   # => 5.0
2.0.sqrt    # => 1.4142135623730951

in?

in?(range: Range<Float>) -> Bool

Returns true when the float falls inside range, endpoints included.

Parameters
range
the inclusive range

Returns true when the float is in range

Examples

Comparing directly is usually clearer for floats

let ratio = 0.75
ratio >= 0.0 && ratio <= 1.0   # => true

floor

floor : Integer

Returns the largest integer that is not greater than the float: it always rounds toward negative infinity, which is what separates it from toInteger for negative values.

Returns the floor

Examples
3.7.floor      # => 3
3.2.floor      # => 3
(-3.2).floor   # => -4

ceil

ceil : Integer

Returns the smallest integer that is not less than the float: it always rounds toward positive infinity.

Returns the ceiling

Examples
3.2.ceil       # => 4
3.0.ceil       # => 3
(-3.7).ceil    # => -3

How many pages of a fixed size a list needs

(items.count.to(Float).or(0.0) / 20.0).ceil

round

round : Integer

Returns the nearest integer, with halves rounding away from zero.

Returns the rounded value

Examples
3.2.round    # => 3
3.5.round    # => 4
3.7.round    # => 4

toInteger

toInteger : Integer

Truncates toward zero and returns the result as an Integer: it drops the fractional part rather than rounding, so it differs from both floor and round for negative values.

Returns the truncated value

Examples
3.7.toInteger      # => 3
(-3.7).toInteger   # => -3   (floor would give -4)

Defined in other modules

module Integer

Reading integers out of text.

Use parse when a failure needs explaining and "42".to(Integer) when it does not: to answers a plain Optional, parse answers a Result carrying a ParseError that says where it stopped and what it had read so far.

parse

parse(s: String) -> Result<Integer, ParseError>
parse(s: String, radix: Integer) -> Result<Integer, ParseError>

Parses the whole string as a base-10 integer.

The string must be entirely consumed: leading or trailing characters make it an Error, with a ParseError describing where parsing stopped. Use parsePrefix when a trailing remainder is expected.

Parameters
s
the text to parse

Returns the integer, or a described failure

Examples
Integer.parse("42")     # => Ok(42)
Integer.parse("-7")     # => Ok(-7)
Integer.parse("4x")     # => Error(ParseError { ... rest: "x" ... })

Reading a setting with a fallback

let port = Integer.parse(raw).or(8080)

Reporting why the input was rejected

match Integer.parse(raw) do
  Ok(n)    => IO.printLine("port ${n}")
  Error(e) => IO.printError("bad port: ${e.message}")
end

parsePrefix

parsePrefix(s: String) -> (Integer, String)?

Parses an integer from the front of the string and returns it together with whatever text was left over.

This is the building block for hand-written scanners: parse a number, keep going from the remainder. Answers None when the string does not begin with a number at all.

Parameters
s
the text to parse from

Returns the value and the unconsumed remainder

Examples
Integer.parsePrefix("42abc")   # => Just((42, "abc"))
Integer.parsePrefix("abc")     # => None

Reading a leading count off a line

match Integer.parsePrefix("3 items") do
  Just(pair) => do
    let (count, rest) = pair
    IO.printLine("${count} of${rest}")   # prints: 3 of items
  end
  None => IO.printError("no leading count")
end

module Float

Reading floating-point numbers out of text.

parse

parse(s: String) -> Result<Float, ParseError>

Parses the whole string as a float.

The string must be entirely consumed; anything left over makes it an Error carrying a ParseError.

Parameters
s
the text to parse

Returns the float, or a described failure

Examples
Float.parse("3.5")     # => Ok(3.5)
Float.parse("-0.25")   # => Ok(-0.25)
Float.parse("3.5m")    # => Error(ParseError { ... rest: "m" ... })

Averaging a column of text values

rows.map { |r| Float.parse(r).or(0.0) }.sum / rows.count.to(Float).or(1.0)

parsePrefix

parsePrefix(s: String) -> (Float, String)?

Parses a float from the front of the string and returns it together with the unconsumed remainder. Answers None when the string does not begin with a number.

Parameters
s
the text to parse from

Returns the value and the remainder

Examples
Float.parsePrefix("3.5rest")   # => Just((3.5, "rest"))
Float.parsePrefix("rest")      # => None

Splitting a measurement from its unit

Float.parsePrefix("12.5kg")   # => Just((12.5, "kg"))

MAX constant

MAX : Float

The largest finite Float.

A Kex Float is always finite, so there is no infinity to start from: this is the bound to use instead, say as the first "smallest so far".

Examples
let smallest = readings.reduce(Float.MAX) { |low, x| x < low then x else low }

MIN constant

MIN : Float

The most negative finite Float: -Float.MAX. Not the smallest positive one, which some languages call MIN.

module Float32

The bounds of the sized numeric types: Int8.MAX, UInt64.MAX, Float32.MIN and so on. Integer has none: it is arbitrary-precision. For a float type, MIN is the most negative finite value, not the smallest positive one.

The range of a 32-bit float.

MAX constant

MAX : Float32

The largest Float32: 3.4028234663852886e38.

MIN constant

MIN : Float32

The most negative finite Float32: -3.4028234663852886e38.

module Float64

The range of a 64-bit float, the same as a Float.

MAX constant

MAX : Float64

The largest Float64: 1.7976931348623157e308.

MIN constant

MIN : Float64

The most negative finite Float64: -1.7976931348623157e308.

module Int8

The range of a signed 8-bit integer.

MAX constant

MAX : Int8

The largest Int8: 127.

MIN constant

MIN : Int8

The smallest Int8: -128.

module Int16

The range of a signed 16-bit integer.

MAX constant

MAX : Int16

The largest Int16: 32767.

MIN constant

MIN : Int16

The smallest Int16: -32768.

module Int32

The range of a signed 32-bit integer.

MAX constant

MAX : Int32

The largest Int32: 2147483647.

MIN constant

MIN : Int32

The smallest Int32: -2147483648.

module Int64

The range of a signed 64-bit integer.

MAX constant

MAX : Int64

The largest Int64: 9223372036854775807.

MIN constant

MIN : Int64

The smallest Int64: -9223372036854775808.

module UInt8

The range of an unsigned 8-bit integer: UInt8 is another name for Byte.

MAX constant

MAX : UInt8

The largest UInt8: 255.

MIN constant

MIN : UInt8

The smallest UInt8: 0.

module UInt16

The range of an unsigned 16-bit integer.

MAX constant

MAX : UInt16

The largest UInt16: 65535.

MIN constant

MIN : UInt16

The smallest UInt16: 0.

module UInt32

The range of an unsigned 32-bit integer.

MAX constant

MAX : UInt32

The largest UInt32: 4294967295.

MIN constant

MIN : UInt32

The smallest UInt32: 0.

module UInt64

The range of an unsigned 64-bit integer.

MAX constant

MAX : UInt64

The largest UInt64: 18446744073709551615.

MIN constant

MIN : UInt64

The smallest UInt64: 0.

module Byte

The range of a Byte, Kex's unsigned 8-bit integer (also called UInt8).

MAX constant

MAX : Byte

The largest Byte: 255.

MIN constant

MIN : Byte

The smallest Byte: 0.

module Number

Reading a number out of text without deciding in advance which half of the numeric tower it belongs to.

parse

parse(s: String) -> Result<Number, ParseError>

Parses the whole string as an Integer or a Float, whichever the text describes.

Use it when the input's shape is not known ahead of time: a config value, a CSV column that may hold either.

Parameters
s
the text to parse

Returns the number, or a described failure

Examples
Number.parse("42")     # => Ok(42)
Number.parse("3.5")    # => Ok(3.5)
Number.parse("x")      # => Error(ParseError { ... })

format

format(parts: [String], values: [Any]) -> NumberFormat

Builds a NumberFormat from a digit pattern, for to(String, format).

The pattern is checked during compilation (by validateFormat), so a mistake in it fails the build instead of leaving text out at run time.

  • 0 is a required digit: 000 pads the integer part to three digits, and .00 always writes two decimals.
  • # is an optional digit: #.## writes at most two decimals and drops trailing zeros. Optional digits come before required ones in the integer part (#0) and after them in the decimals (.0#).
  • . starts the decimals. The value is rounded to as many decimals as the pattern allows, with ties away from zero.

The integer part always has at least one digit, so #.00 writes 0.50, never .50. A value that rounds to zero has no minus sign.

Parameters
parts
the literal pieces of the tagged literal
values
the interpolated values

Returns the format

Examples
1.5.to(String, Number.format`#.00`)   # => Just("1.50")
1.5.to(String, Number.format`#.##`)   # => Just("1.5")
2.0.to(String, Number.format`#.##`)   # => Just("2")
7.to(String, Number.format`000`)      # => Just("007")

validateFormat

validateFormat(source: String) -> [TaggedValidation.Issue]

Checks a Number.format pattern during compilation, pointing at the first character that does not fit.

Parameters
source
the pattern

Returns the problem found, if any

record NumberFormat

How to(String, format) writes a number: a digit pattern such as "#.00", described at Number.format. Build one with Number.format, which checks the pattern during compilation, or with NumberFormat.parse for a pattern known only at run time.

Fields

pattern
String

module NumberFormat

parse

parse(pattern: String) -> Result<NumberFormat, ParseError>

Checks a digit pattern known only at run time. Number.format describes the patterns.

Parameters
pattern
the pattern

Returns the format, or where the pattern goes wrong

Examples
NumberFormat.parse("#.00")   # => Ok(NumberFormat { pattern: "#.00" })
NumberFormat.parse("#.#0")   # => Error(ParseError { position: 3, ... })

layout

layout(pattern: String) -> Result<(Integer, Integer, Integer), (Integer, String)>

What a pattern writes: the fewest integer digits, the fewest decimals and the most decimals. Otherwise the index of its first problem, and what that problem is.

Parameters
pattern
the pattern

Returns the layout, or the problem

Examples
NumberFormat.layout("#0.0##")   # => Ok((1, 1, 3))

type Number

Implements Comparable.

to

to(String: Type, format: NumberFormat) -> String?

Writes the number by a digit pattern, described at Number.format.

Parameters
String
the target type
format
the pattern

Returns the text, or None when the pattern is not valid

Examples
1234.5.to(String, Number.format`#.00`)    # => Just("1234.50")
(-0.001).to(String, Number.format`#.#`)   # => Just("0")
42.to(String, Number.format`0000.0`)      # => Just("0042.0")

leadingZeros

leadingZeros(text: String, width: Integer) -> String

text with leading zeros up to width characters.

trailingZeros

trailingZeros(text: String, width: Integer) -> String

text with exactly width characters if it is shorter, or with its trailing zeros dropped down to width characters if it is longer.

From Comparable

max
What every ordered type gets from compare alone.
min
Returns the smaller of this value and other; this value when they are equal.
clamp
Returns this value limited to the range low to high: low when it is below, high when it is above, and itself otherwise.
<
The ordering operators, from compare alone: whatever is Comparable can be written with < and >, a record as much as a number.

Defined in other modules