kex docs Standard Library 0.4.0-alpha kex.run ↗

Numberprelude

make Integer

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)

modulo

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.

modulo(n) : Integer -> Integer
Parameters
n Integer
the modulus

Returns: Integer — 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?

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

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

Returns: Booltrue 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

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.

times(block) : (Integer -> Void) -> Void
Parameters
f Integer -> Void
called once per iteration with the index

Returns: Void

Examples
3.times { |i| IO.printLine(i) }   # prints 0, then 1, then 2

Repeating an action

retries.times { |_| attemptConnection }

make Float

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)

in?

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

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

Returns: Booltrue 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

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.

function parse

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.

parse(s) : String -> Result<Integer, ParseError>
parse(s) : String -> Integer -> Result<Integer, ParseError>
Parameters
s String
the text to parse

Returns: Result<Integer, ParseError> — 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

function parsePrefix

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.

parsePrefix(s) : String -> (Integer, String)?
Parameters
s String
the text to parse from

Returns: (Integer, String)? — 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.

function parse

Parses the whole string as a float.

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

parse(s) : String -> Result<Float, ParseError>
Parameters
s String
the text to parse

Returns: Result<Float, ParseError> — 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)

function parsePrefix

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.

parsePrefix(s) : String -> (Float, String)?
Parameters
s String
the text to parse from

Returns: (Float, String)? — 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"))

module Number

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

function parse

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.

parse(s) : String -> Result<Number, ParseError>
Parameters
s String
the text to parse

Returns: Result<Number, ParseError> — the number, or a described failure

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