On this page:
7.1 Numbers
Int
+
-
*
/
mod
<
>
<=
>=
min
max
add1
sub1
is_  even
is_  odd
7.2 Booleans and Equality
Boolean
!
==
!=
&&
||
7.3 Void
Void
7.4 Strings
String
string_  append
string_  length
to_  string
+  &
print
println
Char
string_  get
substring
7.5 Symbols
Symbol
#'
string_  to_  symbol
7.6 Lists
Listof
#%brackets
cons
first
rest
is_  cons
is_  empty
length
list_  get
append
reverse
member
map
map2
filter
foldl
foldr
7.7 Arrays
Arrayof
Array
#%index
make_  array
array_  length
7.8 Boxes
Boxof
box
unbox
set_  box
7.9 Options
Optionof
none
some
7.10 Tuples
*
values
fst
snd
#%parens
7.11 Maps
Mapof
#%braces
Mutable  Map
map_  get
map_  get_  k
map_  update
map_  set
map_  remove
map_  delete
map_  keys

7 Predefined Types and Functions🔗ℹ

    7.1 Numbers

    7.2 Booleans and Equality

    7.3 Void

    7.4 Strings

    7.5 Symbols

    7.6 Lists

    7.7 Arrays

    7.8 Boxes

    7.9 Options

    7.10 Tuples

    7.11 Maps

7.1 Numbers🔗ℹ

type

Int

The type for expressions that produce numbers.

expression

expr + expr

 

expression

expr - expr

 

expression

- expr

 

expression

expr * expr

 

expression

expr / expr

 

expression

expr mod expr

Arithmetic on exprs of type Int, and the overall arithmetic expression also has type Int. The integer-division operator / truncates toward 0.

The usual precedence and associativity rules apply, except that / or mod cannot appear to the right of *.

> 1 + 2 * 3 + 8 / 2

- Int

11

> 3 mod 2

- Int

1

> 4 * -(1 + 2)

- Int

-12

expression

expr < expr

 

expression

expr > expr

 

expression

expr <= expr

 

expression

expr >= expr

Numeric comparison on exprs of type Int. The overall comparison expression has type Boolean.

These operators have lower precedence than arithmetic operators.

> 1 + 2 < 4

- Boolean

#true

function

fun min(n :: Int, m :: Int) :: Int

 

function

fun max(n :: Int, m :: Int) :: Int

Functions that compare and select.

> min(1, 2)

- Int

1

> max(1, 2)

- Int

2

function

fun add1(n :: Int) :: Int

 

function

fun sub1(n :: Int) :: Int

Functions that add or subtract 1 from a given number.

> add1(0)

- Int

1

> sub1(0)

- Int

-1

function

fun is_even(n :: Int) :: Boolean

 

function

fun is_odd(n :: Int) :: Boolean

Reports when a number is even or odd, respectively.

> is_even(2)

- Boolean

#true

> is_odd(2)

- Boolean

#false

7.2 Booleans and Equality🔗ℹ

The type for expressions that produce booleans.

expression

! expr

Produces #true when expr produces #false and vice versa.

These operators have lower precedence than arithmetic operators.

> !("apple" == "orange")

- Boolean

#true

expression

expr == expr

 

expression

expr != expr

Compares any two values for (in)equality, as long as the exprs have the same type. The overall comparison expression has type Boolean.

For mutable values, == checks whether the values are equal “now,” even though they may be changed to be different in the future (and != checks that values are not equal now).

> 1 == 1

- Boolean

#true

> "apple" == "orange"

- Boolean

#false

> def b = box(1)

> b == box(1)

- Boolean

#true

> set_box(b, 2)

- Void

> b == box(1)

- Boolean

#false

expression

expr && expr

 

expression

expr || expr

Boolean “and” and “or” in short-circuiting form. That is, if the result of the first expr is #false for && or #true for ||, then the second expression is not evaluated. Both expressions must have type Boolean.

These operators have lower precedence than all other operators, and || has lower precedence than &&.

> 1 == 1  &&  2 == 2

- Boolean

#true

> 1 == 2  ||  2 != 2

- Boolean

#false

7.3 Void🔗ℹ

type

Void

The type for an expression that has a side effect and produces the value #void. For example, the result type of println is Void.

7.4 Strings🔗ℹ

type

String

The type for expressions that produce strings.

function

fun string_append(str1 :: String, str2 :: String) :: String

Appends two strings.

> string_append("apple", "banana")

- String

"applebanana"

function

fun string_length(str :: String) :: Int

Returns the length of str in characters.

function

fun to_string(v :: ?a) :: String

Converts any value to a printed form as a string.

> to_string(1)

- String

"1"

> to_string("apple")

- String

"apple"

> to_string([1, 2, 3])

- String

"[1, 2, 3]"

> to_string(fun (x): x)

- String

"#<function:fun>"

> to_string('fun (x): x')

- String

"fun (x):« x »"

expression

expr +& expr

Converts the result of each expr to a string like to_string, then appends the strings like string_append.

> "a" +& "b"

- String

"ab"

> "a" +& 1

- String

"a1"

> 1 +& "a"

- String

"1a"

> "choices are " +& [1, 2, 3]

- String

"choices are [1, 2, 3]"

function

fun print(v :: ?a) :: Void

 

function

fun println(v :: ?a) :: Void

Converts v to a string using to_string, then prints the string. The println function prints a newline after printing that string.

> println(1 + 2)

3

> block:

    print("a")

    print("b")

    println("")

ab

type

Char

The type of a character within a string.

function

fun string_get(str :: String, i :: Int) :: Char

Returns the ith character of a string, counting from 0.

> string_get("apple", 0)

- Char

#{#\a}

function

fun substring(str :: String, start :: Int, end :: Int) :: String

Returns a substring of str from the character at index start (inclusive) until the character at index end (exclusive).

> substring("apple", 1, 4)

- String

"ppl"

7.5 Symbols🔗ℹ

A symbol is similar to a string in that it simply comprises a sequence of characters, but a symbol expression is written with a #' prefix, instead of in double quotes. Also, the character sequence of a symbol must be valid for an identifier.

Symbols are used primarily as the representation of an identifier within quoted code as a syntax object. For example, the syntax object 'f(apple)' wraps the symbols #'f and #'apple, while 'f("apple")' wraps a symbol #'f and a string "apple". The difference in those examples is between representing a function call whose argument is the variable apple versus a function call whose argument is the string "apple".

type

Symbol

The type for expressions that produce symbols.

expression

#' id

A literal symbol.

> #'apple

- Symbol

#'apple

> "apple"

- String

"apple"

function

fun string_to_symbol(s :: String) :: Symbol

Converts a string to a symbol that has the same character content. Note that to_string converts a symbol to a string.

> string_to_symbol("apple")

- Symbol

#'apple

7.6 Lists🔗ℹ

A list has a sequence of elements of a uniform type. That is, the elements of a list can have any type, but they must all have the same type for a given list. See also tuples.

A list is written with square brackets, such as [1, 2, 3]. Using square brackets implicitly uses the #%brackets form, but #%brackets is normally not written.

The type of a list whose elements have type type.

A list is either empty or a pair of an element and a smaller list:
  • []

  • cons(first_elem, rest_list)

expression

#%brackets [expr, ...]

Produces a list whose elements in order as the values produced by the exprs. All of the exprs must have the same type. Normally, #%brackets is omitted, since it’s implied when using square brackets as an expression form.

> [1, 2, 3 + 4]

- Listof(Int)

[1, 2, 7]

> ["apple", "banana"]

- Listof(String)

["apple", "banana"]

> []

- Listof(?_a)

[]

function

fun cons(elem :: ?a, lst :: Listof(?a)) :: Listof(?a)

 

function

fun first(lst :: Listof(?a)) :: ?a

 

function

fun rest(lst :: Listof(?a)) :: Listof(?a)

 

function

fun is_cons(lst :: Listof(?a)) :: Boolean

 

function

fun is_empty(lst :: Listof(?a)) :: Boolean

The cons function produces a list given its first element plus the rest of the elements already in a list. The first function returns the first element of a nonempty list. The rest function returns a list containing all but the first element of a nonempty list. The is_cons and is_empty functions report whether a list is nonempty or empty, respectively.

The first and rest functions raise an exception when given an empty list. All of these functions take constant time (i.e., independent on the length of lst).

> cons(1, [2, 3])

- Listof(Int)

[1, 2, 3]

> first(["apple", "banana", "coconut"])

- String

"apple"

> rest(["apple", "banana", "coconut"])

- Listof(String)

["banana", "coconut"]

> first([])

- ?_a

first: failed on empty list

function

fun length(lst :: Listof(?a)) :: Int

Returns the number of elements in a list. This function takes time proportional to the length of lst.

> length(["apple", "banana"])

- Int

2

function

fun list_get(lst :: Listof(?a), i :: Int) :: ?a

Returns the ith element of a list, counting from 0. This function takes time proportional to i

> list_get(["apple", "banana"], 1)

- String

"banana"

function

fun append(lst1 :: Listof(?a), lst2 :: Listof(?a)) :: Listof(?a)

Produces a list that has the items of the first given list followed by the items of the second given list. This function takes time proportional to the length of lst1.

> def my_list = [1, 2, 3]

> def my_other_list = [3, 4]

> append(my_list, my_other_list)

- Listof(Int)

[1, 2, 3, 3, 4]

> my_list

- Listof(Int)

[1, 2, 3]

function

fun reverse(lst :: Listof(?a)) :: Listof(?a)

Returns a list that has the same elements as the given one, but in reverse order. This function takes time proportional to the length of lst.

> reverse([1, 2, 3])

- Listof(Int)

[3, 2, 1]

function

fun member(elem :: ?a, lst :: Listof(?a)) :: Boolean

Determines whether a value is an item in a list. Items are compared using ==.

> member(2, [1, 2, 3])

- Boolean

#true

> member(4, [1, 2, 3])

- Boolean

#false

function

fun map(f :: ?a -> ?b, lst :: Listof(?a)) :: Listof(?b)

Applies a function in order to each element of a list and forms a new list with the results.

> map(add1, [1, 2, 3])

- Listof(Int)

[2, 3, 4]

> map(to_string, [1, 2, 3])

- Listof(String)

["1", "2", "3"]

function

fun map2(f :: (?a, ?b) -> ?c, lst1 :: Listof(?a), lst2 :: Listof(?b))

  :: Listof(?c)

Applies a function in order to each pair of elements from two lists in “parallel,” forming a new list with the results. An exception is raised if the two lists have different lengths.

> map2(fun (x, y): x + y, [1, 2, 3], [4, 5, 6])

- Listof(Int)

[5, 7, 9]

function

fun filter(f :: ?a -> Boolean, lst :: Listof(?a)) :: Listof(?a)

Returns a list containing (in order) the items of a given list for which a given function returns true.

> filter(is_even, [1, 2, 3, 4])

- Listof(Int)

[2, 4]

> filter(is_odd, [1, 2, 3, 4])

- Listof(Int)

[1, 3]

function

fun foldl(f :: (?a, ?b) -> ?b, init :: ?b, lst :: Listof(?a))

  :: ?b

 

function

fun foldr(f :: (?a, ?b) -> ?b, init :: ?b, lst :: Listof(?a))

  :: ?b

Applies a function to an accumulated value and each element of a list, each time obtaining a new accumulated value. The second argument to foldl or foldr is the initial accumulated value, and it is provided as the first argument in each call to the given function f. While foldl applies the function to items in the list from first to last, foldr applies the function to items in the list from last to first.

> foldl(fun (x, y): x+y, 10, [1, 2, 3])

- Int

16

> foldl(fun (n, r): cons(to_string(n), r), [], [1, 2, 3])

- Listof(String)

["3", "2", "1"]

> foldr(fun (n, r): cons(to_string(n), r), [], [1, 2, 3])

- Listof(String)

["1", "2", "3"]

7.7 Arrays🔗ℹ

Like a list, an array has a sequence of elements of a uniform type. Unlike a list, any element of the array can be accessed in constant time using square-bracket indexing, as in a[0]. Further unlike a list, an array is mutable, and an array element can be changed by commbining square brackets with := for assignment, as in a[0] = 1.

An array is created with Array, such as Array(1, 2, 3), or with make_array. Using square brackets implicitly uses the #%index form, but #%index is normally not written.

The type of an array whose elements have type type.

expression

Array(expr, ...)

Produces an array whose elements in order are the values produced by the exprs. All of the exprs must have the same type.

> Array(1, 2, 3 + 4)

- Arrayof(Int)

Array(1, 2, 7)

Accesses or updates an array element. Writing out #%index is optional, but be advised that this name will appear in error messages.

> def a = Array("a", "b", "c")

> a[0]

- String

"a"

> a[0] := "z"

- Void

> a[0]

- String

"z"

> a

- Arrayof(String)

Array("z", "b", "c")

> a[0, 0]

#%index: unexpected term

function

fun make_array(n :: Int, val :: ?a) :: Arrayof(?a)

Creates an array with n elements, all initially val.

> make_array(3, "a")

- Arrayof(String)

Array("a", "a", "a")

function

fun array_length(arr :: Arrayof(?a)) :: Int

Returns the number of slots in an array. This function takes constant time.

> array_length(Array("a", "b", "c"))

- Int

3

7.8 Boxes🔗ℹ

A box is a mutable object that holds a single value.

type

Boxof(type)

The type of a box that holds a type value.

function

fun box(val :: ?a) :: Boxof(?a)

 

function

fun unbox(bx :: Boxof(?a)) :: ?a

 

function

fun set_box(bx :: Boxof(?a), val :: ?a) :: Void

The box function produces a box that is distinct from all existing boxes and that initially holds val. The unbox function extracts the current value of a box, and the set_box function changes the value that is held by a box.

> def b = box(1)

> b

- Boxof(Int)

box(1)

> unbox(b)

- Int

1

> set_box(b, 2)

- Void

> unbox(b)

- Int

2

> set_box(b, "apple")

typecheck failed: Int vs. String

7.9 Options🔗ℹ

An option encapsulates the idea of a computation that may fail.

The type of an option that optionally holds a type value.

An option is either a “failure” without a value or “success” with a value:

function

fun none() :: Optionof(?a)

 

function

fun some(v :: ?a) :: Optionof(?a)

Produces a “failure” or “success” option.

7.10 Tuples🔗ℹ

A tuple is similar to a list, but its type reflects a fixed number of elements in the tuple, and the elements can have different types. A tuple of one element is equivalent to just the element.

type

type * type ... * type

The type of a tuple whose elements each have the corresponding type. The type of an empty tuple is written as ().

The * type operator for tuples has higher precedence (i.e., joins more tightly) than the -> type operator for functions.

> values(1, "apple")

- Int * String

values(1, "apple")

> values()

- ()

values()

> values(1, fun (x :: Int): x)

- Int * (Int -> Int)

values(1, #<function:fun>)

expression

values(expr, ...)

Creates a tuple whose elements are produced by the exprs.

In general extract components of a tuple by using def values.

> def tup = values(1, "apple", fun (x): x)

> tup

- Int * String * (?a -> ?a)

values(1, "apple", #<function:fun>)

> def values(n, str, id_func) = tup

> str

- String

"apple"

function

fun fst(tup :: ?a * ?b) :: ?a

 

function

fun snd(tup :: ?a * ?b) :: ?b

Convenience functions for 2-element tuples to extract the first or second component, respectively.

type

#%parens ()

 

type

#%parens (type)

The #%parens type form is generally not written out, but it is implicitly used whenever a Shplait program uses parentheses in a type position.

Parentheses are normally used for mere grouping, but emprt parentheses form the type of an empty tuple.

7.11 Maps🔗ℹ

A map (not to be confused with the map function on lists), also known as a dictionary, is a mapping from keys to values. All keys must have the same type, and all values must have the same type.

A map is written with curly braces {} around comma-separated key–value pairs, where the key and value are separated by a colon :, as in {"a": 1, "b": 2}. Using curly braces implicitly uses the #%braces form, but #%braces is normally not written.

The type of a map whose keys are of type key_type and values (that keys map to) are of type val_type.

expression

#%braces { key_expr: val_expr, ... }

Produces an immutable map whose keys are the values produced by the key_exprs mapping each of them to the value produced by the corresponding val_expr. All of the key_exprs must have the same type, and all of the val_exprs must have the same type. Normally, #%braces is omitted, since it’s implied when using square brackets as an expression form.

Since the result map is immutable, it works with map_update, but not map_set.

> { "a": 1, "b": 2 }

- Mapof(String, Int)

{"a": 1, "b": 2}

expression

MutableMap{ key_expr: val_expr, ... }

Produces a mutable map whose keys and values are initially the same as the map produced by the same expression without MutableMap.

Since the result map is mutable, it works with map_set, but not map_update.

> MutableMap{ "a": 1, "b": 2 }

- Mapof(String, Int)

MutableMap{"a": 1, "b": 2}

function

fun map_get(map :: Mapof(?a, ?b), key :: ?a) :: Optionof(?b)

 

function

fun map_get_k(map :: Mapof(?a, ?b), key :: ?a,

              success_k :: ?a -> ?c,

              fail_k :: () -> ?c) :: ?c

Functions to look up a key in a map. Since the key might not be mapped to a value, the value cannot be returned directly. Instead, map_get returns some(val) if key is mapped to val and none() if key is not mapped to a value.

The map_get_k function calls either success_k or fail_k and returns the result, depending on whether key is mapped. The call map_get(map, key) is equivalent to map_get_k(map, key, some, none).

> def m = { "a": 1, "b": 2 }

> map_get(m, "a")

- Optionof(Int)

some(1)

> map_get(m, "c")

- Optionof(Int)

none()

> map_get_k(m, "a", fun(v): v, fun(): 0)

- Int

1

> map_get_k(m, "c", fun(v): v, fun(): 0)

- Int

0

function

fun map_update(map :: Mapof(?a, ?b), key :: ?a, val :: ?b)

  :: Mapof(?a, ?b)

Produces a new map that is like map, but with key mapped to val. The given map must be immutable.

> def m = { "a": 1, "b": 2 }

> map_update(m, "a", 100)

- Mapof(String, Int)

{"a": 100, "b": 2}

> map_update(m, "c", 3)

- Mapof(String, Int)

{"a": 1, "b": 2, "c": 3}

> m

- Mapof(String, Int)

{"a": 1, "b": 2}

function

fun map_set(map :: Mapof(?a, ?b), key :: ?a, val :: ?b) :: Void

Changes map so that key is mapped to val. The given map must be mutable.

> def m = MutableMap{ "a": 1, "b": 2 }

> map_set(m, "a", 100)

- Void

> map_set(m, "c", 3)

- Void

> m

- Mapof(String, Int)

MutableMap{"a": 100, "b": 2, "c": 3}

function

fun map_remove(map :: Mapof(?a, ?b), key :: ?a) :: Mapof(?a, ?b)

 

function

fun map_delete(map :: Mapof(?a, ?b), key :: ?a) :: Void

The map_remove function works only on immutable maps, and it returns a new map without a mapping for key, if there is one. The map_delete function works only on mutable maps, and it modifies the map to remove a mapping for key, if there is one.

> map_remove({ "a": 1, "b": 2}, "a")

- Mapof(String, Int)

{"b": 2}

> def m = MutableMap{ "a": 1, "b": 2 }

> map_delete(m, "a")

- Void

> m

- Mapof(String, Int)

MutableMap{"b": 2}

function

fun map_keys(map :: Mapof(?a, ?b)) :: Listof(?a)

Returns a list of keys mapped by map.

> map_keys({ "a": 1, "b": 2 })

- Listof(String)

["b", "a"]