Built-in functions
N provides many built-in functions that are available to use globally without needing to import anything.
Contents
Basics
int.toString
: () -> str
Converts an integer to a string.
assert value (10).toString() = "10"
NOTE: To convert a float to a string, use the stringify
function from the json
built-in module.
NOTE: To parse a string as an integer or float, use the parse
or parseSafe
function from the json
module.
int.toFloat
: () -> float
Converts an integer to a float. Inverse of round
, floor
, and ceil
.
assert value (3).toFloat() == 3.0
float.round
: () -> int
Converts a float to an integer. Non-integers are rounded to the nearest integer; if the fractional part is 0.5, then it is rounded up. Inverse of toFloat
.
assert value (10.5).round() == 11
assert value (-10.5).round() == -10
NOTE: The behavior for round
, floor
, and ceil
when given an infinity or NaN is undefined. See nbuilding/N-lang#243.
float.floor
: () -> int
Converts a float to an integer, rounding down. Inverse of toFloat
.
assert value (10.5).floor() == 10
assert value (-10.5).floor() == -11
float.ceil
: () -> int
Converts a float to an integer, rounding up. Inverse of toFloat
.
assert value (10.5).ceil() == 11
assert value (10.4).ceil() == 11
assert value (-10.5).ceil() == -10
char.charCode
: () -> int
Gets the Unicode code point value for the given character. Inverse of intCode
.
assert value \{a}.charCode() == 97
assert value \{🕴}.charCode() == 0x1f574
int.intCode
: () -> char
Converts the given Unicode code point to the corresponding character. Invalid code points are converted to � (U+FFFD, REPLACEMENT CHARACTER). Inverse of charCode
.
assert value (32).intCode() == \{ }
assert value (-1).intCode() == \u{FFFD}
str.charAt
: (int) -> maybe[char]
Gets the character (not grapheme or code point) at the given index. Since strings are probably not stored in UTF-32, this is probably O(n), but this is implementation-defined. Negative indices aren't supported.
assert value "abc".charAt(1) == yes(\{b})
assert value "abc".charAt(-1) == none
NOTE: N now has a special character access syntax that should be used instead: string[index]
.
str.substring
: (int, int) -> str
Gets a portion of a string given a start index (inclusive) then the end index (exclusive). The indices work as they do in Python, so they support negative indices; however, if the start index is after the end index, then substring
returns an empty string.
assert value "abc".substring(0, 2) == "ab"
assert value "apple sauce".substring(-3, -1) == "uc"
assert value "banana jam".substring(0, -1) == "banana ja"
assert value "hi".substring(0, 100) == "hi"
assert value "hi".substring(2, 100) == ""
assert value "hello world".substring(5, 3) == ""
str.split
: (char) -> list[str]
Splits the given string by a character. Returns an empty array for an empty string.
assert value split(\{b}, "abc") == ["a", "c"]
assert value split(\{b}, "") == []
assert value split(\{b}, "apple") == ["apple"]
str.strip
: () -> str
Removes whitespace characters.
assert value " abc ".strip() == "abc"
NOTE: The characters removed by strip
are implementation-defined. See nbuilding/N-lang#245.
Lists
list[t].len
: () -> int
Gets the length of the given value. The behavior of len
depends on the type of value given; if the argument is a string or list, then it'll return its length (for strings, this is in Unicode characters, not code points or graphemes). Otherwise, it'll return zero.
assert value "abc".len() == 3
assert value (100).len() == 0
list[t].itemAt
: [t] (int) -> maybe[t]
Gets the item of a list by index. Does not support negative indices.
assert value [1, 2, 3]itemAt(1) == yes(2)
assert value [1, 2, 3].itemAt(-1) == none
NOTE: N now has a special list item access syntax that should be used instead: list[index]
.
NOTE: The representation of lists in memory is implementation-defined, so item access may be O(n) in the worst case.
list[t].append
: [t] (t) -> list[t]
Returns a new list with the given item added to the end of the given list.
let list == [1, 2, 3]
assert value append(4, list) == [1, 2, 3, 4]
assert value list == [1, 2, 3]
NOTE: append
does not mutate the list.
list[t].subsection
: [t] (int, int) -> list[t]
Returns a list containing a portion of the items in the given list; analogous to substring
but for lists.
assert value [0, 1, 2, 3, 4, 5].subsection(2, 4) == [2, 3]
assert value [0, 1, 2, 3, 4, 5].subsection(4, 1000) == [4, 5]
assert value [1, 2, 3].subsection(-3, -5) == []
assert value [1, 2, 3].subsection(-3, 1) == [1]
assert value [1, 2, 3].subsection(3, 2) == []
list[a].filterMap
: [a, b] ((a) -> maybe[b]) -> list[b]
Applies the given function to each item in the given list. If the function returns none
, the item will not be included in the list; otherwise, the contained value in the maybe
value will be included in the new list. Returns a new list containing the resulting yes
-contained values given by the function.
filterMap
is intentionally generalized because filter
and map
can be easily defined in terms of filterMap
.
assert value [0, 1, 2, 3, 4].filterMap([value:int] -> maybe[int] {
return yes(value * value + 1)
}) == [1, 2, 5, 10, 17]
range
: (int, int, int) -> list[int]
Returns a list of integers within the specified range. This takes a starting value (inclusive), an end value (exclusive), and a step value. This is based on Python's range
constructor, so it supports negative step values.
range
is intended to be used with for
loops to loop over a range of integers.
assert value range(0, 3, 1) == [0, 1, 2]
assert value range(0, 10, 1) == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
assert value range(1, 11, 1) == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
assert value range(0, 30, 5) == [0, 5, 10, 15, 20, 25]
assert value range(0, 10, 3) == [0, 3, 6, 9]
assert value range(0, -10, -1) == [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
assert value range(0, 0, 1) == []
assert value range(1, 0, 1) == []
NOTE: The representation of lists in memory is implementation-defined, so an implementation may attempt to store the entire list in memory. This may be costly for performance when iterating over a large range.
str.parseInt
: () -> maybe[int]
Returns an int if it able to parse the string into a base 10 integer, will return none if it fails
assert value "asdf".parseInt() == none
assert value "10".parseInt() == 10
str.parseFloat
: () -> maybe[float]
Returns a int if it able to parse the string into a base 10 float, will return none if it fails or if the value is not finite
assert value "asdf".parseInt() == none
assert value "nan".parseInt() == none
assert value "inf".parseInt() == none
assert value "-inf".parseInt() == none
assert value "10.34".parseInt() == 10
exit
: (int) -> ()
Exits the program with the given exit code
print("test")
exit(0)
print("this will never run")
Maps
mapFrom
: [k, v] (list[(k, v)]) -> map[k, v]
Creates a map from the given list of key-value pairs. Inverse of entries
.
let map == mapFrom([("a", 1), ("b", 2)])
assert type map : map[str, int]
NOTE: Maps allow functions and commands as keys, but the behavior of these maps is undefined.
entries
: [k, v] (map[k, v]) -> list[(k, v)]
Returns a list of key-value pairs from the map. Inverse of mapFrom
.
assert value entries(map) == [("a", 1), ("b", 2)]
NOTE: The order of the key-value pairs should be preserved.
getValue
: [k, v] (k, map[k, v]) -> maybe[v]
Gets a value from the given map by the given key.
assert value getValue("b", map) == yes(2)
assert value getValue("c", map) == none
NOTE: N now has a special map value access syntax that should be used instead: map[key]
.
NOTE: The value access algorithm is implementation-defined and may be O(n) in the worst case.
maybe
values
maybe[t].default
: [t] (t) -> t
Given a default value and a maybe
value, returns the default value if the maybe
value is none
; otherwise, it returns the value contained in the maybe
value.
assert value yes("test").default("test1") == "test"
assert value none.default("test1") == "test1"
This is equivalent to:
let default = [t] (defaultValue:t, maybe:maybe[t]) -> t {
if let yes(value) = maybe {
return value
} else {
return defaultValue
}
}
Commands
then
: [a, b] ((a) -> cmd[b], cmd[a]) -> cmd[b]
Returns a new command that first executes the given command, then runs the given function given the result from the given command, then executes the resulting command from that function.
import FileIO
assert type then([text: maybe[str]] -> cmd[()] {
assert value len(text |> default("")) > 0
}, FileIO.read("./README.md")) : cmd[()]
This is equivalent to:
let then = [[a, b] function:(a -> cmd[b]) command:cmd[a]] -> cmd[b] {
return function(command!)
}
parallel
: [t] (cmd[t]) -> cmd[cmd[t]]
Returns a new command that executes the given command in parallel. The result of this new command is another command that resolves when the given command finishes executing.
You can use the resulting command of the command returned by parallel
to wait for the command running in parallel to finish.
let parallelCmd = () |> ([] -> cmd[()] {
let _ = parallel(() |> ([] -> cmd[()] {
assert value true
}))!
})
NOTE: The program exits when the main command finishes, so commands running in parallel will be stopped.
Printing for debugging
printWithEnd
: [t] (str, t) -> t
Prints the given value to stdout followed by the specified string and flushes, then returns the value. Non-string values are pretty-printed in an implementation-defined manner.
let printed = 3.14
|> printWithEnd(" ")
assert value printed == 3.14
NOTE: This function is impure, but it is not a procedure for convenience. Thus, this should only be used for development and debugging purposes, not for actual output to stdout.
print
: [t] (t) -> t
Equivalent to printWithEnd("\n")
and thus shares its caveats.
assert value print("test") = "test"
Runtime unit tests
intoModule
: [m] (m) -> maybe[module]
Attempts to convert the given type to a module
value. Imports from imp
will be successfully converted to a module
; intoModule
will return none
for all other values.
See getUnitTestResults
below for an example.
module.getUnitTestResults
: () -> list[{ hasPassed: bool, fileLine: int, unitTestType: str, possibleTypes: maybe[(str, str)] }]
Gets a list of assertion results from the given module
value. Assertion results are a record with fields that depend on the type of assertion used in the module.
Results from both assert type
and assert value
will include a hasPassed
field, a boolean that represents whether the assertion passed.
assert type
results also have the following fields:
fileLine
, which is always0
unitTestType
, which is always the string"type"
possibleTypes
, which is a tuple containing implementation-defined strings (meant to be displayed to the user) wrapped inyes
.
assert value
results have the following fields:
fileLine
, an integer representing the line the assertion was onunitTestType
, which is always the string"value"
possibleTypes
, which is alwaysnone
if let yes(module) = intoModule(imp "./imports/unit-test.n") {
let results = module.getUnitTestResults()
assert value len(results) == 4
assert value (results |> itemAt(0)) == yes({
hasPassed: true
fileLine: 3
unitTestType: "value"
possibleTypes: none
})
assert value (results |> itemAt(1)) == yes({
hasPassed: false
fileLine: 5
unitTestType: "value"
possibleTypes: none
})
for (result in (results |> subsection(2, 4))) {
assert value result.hasPassed
assert value result.unitTestType == "type"
assert value if let yes(_) == result.possibleTypes { true } else { false }
}
assert value (results |> itemAt(2) |> default({
hasPassed: true
fileLine: 0
unitTestType: "value"
possibleTypes: none
})).fileLine == 7
assert value (results |> itemAt(3) |> default({
hasPassed: true
fileLine: 0
unitTestType: "value"
possibleTypes: none
})).fileLine == 9
}