CSL standard library source code

// CSL standard library
////////////////////////

/////////
// Errors
/////////

/// error : RuntimeError -> a
val error = prim__error

//////////////////////
// General combinators
//////////////////////

/// The identity function.  'id' simply returns the input.
///
/// Examples:
/// id 4 = 4
/// id "a" = "a"
///
val <a> id : a -> a = \x -> x

/// The constant function.  'const x' is a function which returns 'x', no matter what input it is given.
///
/// Examples:
/// const "a" "b" = "a"
///
val <a, b> const : a -> b -> a = \x -> \_ -> x

/// Flips the order of the arguments for a binary function.
///
/// Examples:
/// flip (\x -> \y -> x) "a" "b" = "b"
///
val <a, b, c> flip : (a -> b -> c) -> (b -> a -> c) = \f -> \y -> \x -> f x y

/// Composes two unary functions.
///
/// Examples:
/// comp (\x -> x + 5) (\y -> y * 12) 5 = (\x -> x + 5) 60 = 65
///
val <a, b, c> comp : (a -> b) -> (c -> a) -> c -> b = \f -> \g -> \x -> f (g x)

/// 'via f g x y' transforms 'x' and 'y' using unary function 'f' and applies the results to binary function 'g'.
///
/// Examples:
/// via fst compareInt (1, 3.15) (2, 0.75) = Less
/// via snd compareInt (1, 3.15) (2, 0.75) = Greater
///
val <a, b, c> via : (a -> b) -> (b -> b -> c) -> (a -> a -> c) =
  \f -> \g -> \x -> \y -> g (f x) (f y)

/// Returns the smaller of the two last arguments, using the comparison function
/// provided as the first argument.
///
/// Examples:
/// min compareInt 8 9 = 8
/// min compareFloat 4.233 3.11 = 3.11
///
val <a> min : (a -> a -> Ordering) -> a -> a -> a =
  \cmp -> \el1 -> \el2 -> if (cmp el1 el2 = Less) el1 else el2

/// Returns the larger of the two last arguments, using the comparison function
/// provided as the first argument.
///
/// Examples:
/// max compareInt 8 9 = 9
/// max compareFloat 4.233 3.11 = 4.233
///
val <a> max : (a -> a -> Ordering) -> a -> a -> a =
  \cmp -> \el1 -> \el2 -> if (cmp el1 el2 = Greater) el1 else el2

//////////////////////
// Bool
//////////////////////

/// The 'not' function returns the opposite value of its input.
///
/// Examples:
/// not True = False
/// not False = True
///
val not : Bool -> Bool =
  \ True -> False
  | False -> True

//////////////////////
// Pair
//////////////////////

/// The first projection.
///
/// Examples:
/// fst (0, "a") = 0
///
val <a, b> fst : Tuple a b -> a = \(x, _) -> x

/// The second projection.
///
/// Examples:
/// snd (0, "a") = "a"
///
val <a, b> snd : Tuple a b -> b = \(_, y) -> y


//////////////////////
// Maybe
//////////////////////

/// The 'maybe' function takes a default value, a function, and a 'Maybe' value.
/// The default value is returned if the 'Maybe' value is 'None', otherwise the
/// result of applying the function to the value inside the 'Some' is returned.
///
/// Examples:
/// maybe 0 (\x -> x + 5) (Some 2) = 7
/// maybe 0 (\x -> x + 5) None = 0
///
val <a, b> maybe : b -> (a -> b) -> Maybe a -> b = \default -> \f ->
  \ None   -> default
  | Some x -> f x

/// The 'fromMaybe' function extracts the value from a 'Maybe', using the
/// default value for the 'None' case.
///
/// Examples:
/// fromMaybe 0 (Some 5) = 5
/// fromMaybe 0 None = 0
///
/// fromMaybe : a -> Maybe a -> a
val <a> fromMaybe : a -> Maybe a -> a = flip maybe id

module Maybe {
  /// Lift any function to a function in 'Maybe'.
  ///
  /// Examples:
  /// map (\m -> m * 2) (Some 5) = Some 10
  /// map (\m -> m * 2) None = None
  ///
  val <a, b> map : (a -> b) -> Maybe a -> Maybe b = \f ->
    \ None -> None
    | Some x -> Some (f x)

  /// Lift any binary function to a function in 'Maybe'.
  ///
  /// Examples:
  /// map2 (\x -> \y -> x + y) (Some 7) (Some 5) = Some 12
  /// map2 (\x -> \y -> x + y) (Some 7) None = None
  /// map2 (\x -> \y -> x + y) None (Some 5) = None
  /// map2 (\x -> \y -> x + y) None None = None
  ///
  val <a, b, c> map2 : (a -> b -> c) -> Maybe a -> Maybe b -> Maybe c = \f ->
    \ None -> const None
    | Some x ->
      \ None -> None
      | Some y -> Some (f x y)

  /// Returns 'True' if the input is a 'Some', returns 'False' otherwise.
  ///
  /// Examples:
  /// isSome (Some 2) = True
  /// isSome None = False
  ///
  val <a> isSome : Maybe a -> Bool =
    \ None -> False
    | Some _ -> True

  /// Returns 'True' if, and only if, the given 'Maybe' has a value, and this value satisfies
  /// the given predicate.
  ///
  /// Examples:
  /// any (\n -> n > 4) (Some 5) = True
  /// any (\n -> n > 4) (Some 2) = False
  /// any (\n -> n > 4) None = False
  ///
  val <a> any : (a -> Bool) -> Maybe a -> Bool = \pred -> maybe False pred

  /// Returns 'True' if the given 'Maybe' has no value, or it has a value which
  /// satisfies the given predicate.
  ///
  /// Examples:
  /// all (\x -> x >= 1) None = True
  /// all (\x -> x >= 1) (Some 2) = True
  /// all (\x -> x >= 1) (Some 0) = False
  ///
  val <a> all : (a -> Bool) -> Maybe a -> Bool = \pred -> maybe True pred

  /// Apply the function 'f' to the value 'a' if
  /// the Maybe is 'Some a', 'None' otherwise.
  /// 'f' must return a 'Maybe' type.
  ///
  /// Examples:
  /// bind (\x -> Some (x + 1)) None = None
  /// bind (\x -> None) (Some 1) = None
  /// bind (\x -> Some (x + 1)) (Some 1) = Some 2
  ///
  val <a, b> bind : (a -> Maybe b) -> Maybe a -> Maybe b = \f ->
    \ None -> None
    | Some x -> f x

}


//////////////////////
// Ordering
//////////////////////

val compareInt : Int -> Int -> Ordering = \(x : Int) -> \y ->
  if (x < y) Less else if (x = y) Equal else Greater

val compareFloat : Float -> Float -> Ordering = \(x : Float) -> \y ->
  if (x < y) Less else if (x = y) Equal else Greater

val compareInstant : Instant -> Instant -> Ordering = \(x : Instant) -> \y ->
  if (x < y) Less else if (x = y) Equal else Greater

val compareDate : Date -> Date -> Ordering = \(x: Date) -> \y ->
  if (x < y) Less else if (x = y) Equal else Greater

val compareTime : Time -> Time -> Ordering = \(x: Time) -> \y ->
  if (x < y) Less else if (x = y) Equal else Greater

module Ordering {

  /// Ordering combinator 'twoStep' takes two functions comparing a given type.
  /// When comparing concrete arguments, if the first comparison function
  /// returns 'Equal', the second one is used to decide the comparison.
  ///
  /// Examples:
  /// twoStep
  ///   (\(x1, x2) -> \(y1, y2) -> compareInt x1 y1)
  ///   (\(x1, x2) -> \(y1, y2) -> compareFloat x2 y2)
  ///   (5, 99.9) (7, 15.599) = Less
  /// type R { a : Float, b: Int}
  /// twoStep
  ///   (\x -> \y -> compareFloat (x.a) (y.a))
  ///   (\x -> \y -> compareInt (x.b) (y.b))
  ///   R {a = 3.14, b = 6} R {a = 3.14, b = 2} = Greater
  ///
  val <a> twoStep : (a -> a -> Ordering) -> (a -> a -> Ordering) -> a -> a -> Ordering =
    \ord1 -> \ord2 -> \v1 -> \v2 -> let
      val res1 = ord1 v1 v2
      in if (res1 = Equal) (ord2 v1 v2) else res1

  /// Ordering combinator 'lexicographic' builds an ordering function for a binary tuple.
  /// It takes two arguments, comparison functions for the first and the second element of the tuple,
  /// and returns a lexicographic comparison on the tuples.
  ///
  /// Examples:
  /// lexicographic compareInt compareFloat (5, 99.9) (7, 15.599) = Less
  /// lexicographic compareInt compareFloat (5, 17.0) (5, 16.9) = Greater
  ///
  val <a, b> lexicographic : (a -> a -> Ordering) -> (b -> b -> Ordering) -> Tuple a b -> Tuple a b -> Ordering =
    \ord1 -> \ord2 ->
      twoStep (\v1 -> \v2 -> ord1 (fst v1) (fst v2)) (\v1 -> \v2 -> ord2 (snd v1) (snd v2))

}

//////////////////////
// List
//////////////////////

val <a, b> foldl : (b -> a -> b) -> b -> List a -> b = prim__foldl

val <a, b> foldr : (a -> b -> b) -> b -> List a -> b = prim__foldr

module List {

  /// Returns the head (i.e. the first element) of the list, if any.  Otherwise
  /// returns 'None'.
  ///
  /// Examples:
  /// head [0] = Some 0
  /// head [] = None
  ///
  val <a> head : List a -> Maybe a =
    \ Nil -> None
    | Cons x _ -> Some x

  /// Returns the head (i.e. the first element) of a list, if any.  Otherwise
  /// returns the given default value.
  ///
  /// Examples:
  /// headOrDefault 42 [0] = 0
  /// headOrDefault 42 [] = 42
  ///
  val <a> headOrDefault : a -> List a -> a = \default -> \xs -> fromMaybe default (head xs)

  /// Returns the tail of a list (i.e. what remains when stripping away the
  /// first element), if any.  Otherwise, if the list is empty, return 'None'.
  ///
  /// Examples:
  /// tail [0, 1] = Some [1]
  /// tail [0] = Some []
  /// tail [] = None
  ///
  val <a> tail : List a -> Maybe (List a) =
    \ Nil -> None
    | Cons _ xs -> Some xs

  /// Returns the minimum of a list, if any. Uses the ordering function provided
  /// as the first argument to compare elements.
  ///
  /// Examples:
  /// minimum compareInt [] = None
  /// minimum compareInt [1, 6, 0, 234, 2] = Some 0
  val <a> minimum : (a -> a -> Ordering) -> List a -> Maybe a = \cmp -> \lst ->
    Maybe::map2 (foldl (min cmp)) (head lst) (tail lst)

  /// Returns the maximum of a list, if any. Uses the ordering function provided
  /// as the first argument to compare elements.
  ///
  /// Examples:
  /// maximum compareInt [] = None
  /// maximum compareInt [1, 6, 0, 234, 2] = Some 234
  val <a> maximum : (a -> a -> Ordering) -> List a -> Maybe a = \cmp -> \lst ->
    Maybe::map2 (foldl (max cmp)) (head lst) (tail lst)

  /// Returns 'True' if the list contains the given value.
  /// Otherwise it returns 'False'.
  ///
  /// Examples:
  /// contains 5 [] = False
  /// contains 3.5 [0.0, 3.5, 7.0] = True
  ///
  val <a: Ord> contains : a -> List a -> Bool = prim__List_contains

  /// The 'sort' function takes an ordering function and a list,
  /// and returns an ordered list.
  ///
  /// Examples:
  /// sort compareInt [4, 2, 3]
  ///   = [2, 3, 4]
  ///
  val <a> sort : (a -> a -> Ordering) -> List a -> List a = prim__List_sort

  /// The 'isSorted' function takes an ordering function and a list,
  /// and returns True, if the list is ordered. Otherwise returns 'False'.
  ///
  /// Examples:
  /// isSorted compareInt []
  ///  = True
  /// isSorted compareInt [1, 3, 3, 6]
  ///  = True
  /// isSorted compareInt [1, 6, 3]
  ///  = False
  ///
  val <a> isSorted : (a -> a -> Ordering) -> List a -> Bool = \ordering -> \lst -> let
    val step =
      \ (False, _) as acc -> const acc
      | (True, None) -> (\curr -> (True, Some curr))
      | (True, Some prev) -> \curr -> let
        val unexpectedOrder = ordering prev curr = Greater
        in (not unexpectedOrder, Some curr)
    in fst (foldl step (True, None) lst)

  /// The 'length' function returns the number of elements in a list.
  /// Examples:
  /// length ["a", "b", "c"] = 3
  /// length [] = 0
  ///
  val <a> length : List a -> Int = foldl (\n -> \_ -> n + 1) 0

  /// 'isEmpty' returns True if a list is empty. False otherwise.
  ///
  /// Examples
  /// isEmpty [1, 2, 3]
  ///    = False
  ///
  val <a> isEmpty : List a -> Bool =
    \ Nil -> True
    | _ -> False

  /// 'map f xs' is the list obtained by applying the function f on each of the
  /// elements in the list 'xs'.
  ///
  /// Examples:
  /// map (\n -> n * 2) [1, 2, 3]
  ///   = [2, 4, 6]
  ///
  val <a, b> map : (a -> b) -> List a -> List b =
    \f -> foldr (\x -> \ys -> Cons (f x) ys) Nil

  /// The 'mapMaybe' function is a version of 'map' which takes a partial function,
  /// and throws away the undefined value (i.e. the 'None's).
  ///
  /// Examples:
  /// mapMaybe (\n -> if (n > 100) (Some n) else None) [140, 40, 103]
  ///   = [140, 103]
  ///
  /// mapMaybe id [Some "a", None, Some "b"]
  ///   = ["a", "b"]
  ///
  val <a, b> mapMaybe : (a -> Maybe b) -> List a -> List b =
    \f -> foldr (\x -> \acc -> maybe acc (\y -> Cons y acc) (f x)) Nil

  /// The 'filter' function takes a predicate and a list, and returns a list
  /// consisting of the elements of the input list which satisfies the predicate.
  ///
  /// Examples:
  /// filter (\n -> n < 10) [10, 1, 2, 100]
  ///   = [1, 2]
  ///
  val <a> filter : (a -> Bool) -> List a -> List a =
    \f -> foldr (\y -> \ys -> if (f y) Cons y ys else ys) Nil

  /// The 'zipWith' function generalises 'map' to binary functions.  It takes
  /// a binary function and two lists as arguments, and returns a list
  /// resulting from applying the function pairwise on the elements of the
  /// lists.
  /// The resulting list always has the same length as the shortest input list.
  ///
  /// Examples:
  /// zipWith (\m -> \n -> m + n) [4, 5] [10, 20]
  ///   = [14, 25]
  ///
  /// zipWith (\m -> \n -> m + n) [4, 5] [10]
  ///   = [14]
  ///
  /// zipWith (\m -> \n -> m + n) [4] [10, 20]
  ///   = [14]
  ///
  val <a, b, c> zipWith : (a -> b -> c) -> List a -> List b -> List c = \f ->
    let val step = \a -> \g ->
      \ Nil -> Nil
      | Cons b bs -> Cons (f a b) (g bs)
    in foldr step (\_ -> Nil)

  /// The 'zip' function takes two lists as arguments, and returns a
  /// list of the elements pairwise together.
  /// The resulting list always has the same length as the shortest input list.
  ///
  /// Examples:
  /// zip [1,2] ["a", "b"]
  ///   = [(1, "a"), (2, "b")]
  ///
  /// zip [] ["a"]
  ///   = []
  ///
  /// zip [(1,"a"), (2,"b")] [True, False]
  ///   = [((1,"a"),True), ((2,"b"), False)]
  ///
  val <a, b> zip : List a -> List b -> List (Tuple a b) = List::zipWith (\a -> \b -> (a, b))

  /// Given a predicate and a list, 'any' returns 'True' if, and only if, there
  /// exists an element in the list which satisfies the predicate.
  ///
  /// Examples:
  /// any (\n -> n > 4) [2, 10] = True
  /// any (\n -> n > 4) [2, 0] = False
  /// any (\n -> n > 4) [] = False
  ///
  val <a> any : (a -> Bool) -> List a -> Bool =
    \pred -> foldl (\b -> \x -> b || pred x) False

  /// Given a predicate and a list, 'all' returns 'True' if, and only if, all
  /// elements in the list satisfy the predicate.
  ///
  /// Examples:
  /// all (\n -> n > 4) [5, 6] = True
  /// all (\n -> n > 4) [5, 3] = False
  /// all (\n -> n > 4) [] = True
  ///
  val <a> all : (a -> Bool) -> List a -> Bool =
    \pred -> foldl (\b -> \x -> b && pred x) True

  /// Returns the first element in the list which satisfies the predicate,
  /// if any.
  ///
  /// Examples:
  /// first (\n -> n > 4) [3, 42, 100]
  ///   = Some 42
  ///
  /// first (\n -> n > 4) [3, 2, 1]
  ///   = None
  ///
  val <a> first : (a -> Bool) -> List a -> Maybe a =
    \pred -> foldr (\x -> \acc -> if (pred x) (Some x) else acc) None

  /// Returns the last element in the list which satisfies the predicate,
  /// if any.
  ///
  /// Examples:
  /// last (\n -> n > 4) [3, 42, 100]
  ///   = Some 100
  ///
  /// last (\n -> n > 4) [3, 2, 1]
  ///   = None
  ///
  val <a> last : (a -> Bool) -> List a -> Maybe a =
     \pred -> foldl (\acc -> \x -> if (pred x) (Some x) else acc) None

  /// Appends two lists.
  ///
  /// Examples:
  /// append ["a"] ["b"]
  ///   = ["a", "b"]
  ///
  /// append [] ys = ys
  ///
  /// append xs [] = xs
  ///
  val <a> append : List a -> List a -> List a =
    \xs -> \ys -> foldr (\x -> \acc -> Cons x acc) ys xs

  /// Flattens a list of lists into one list, by appending them to each other.
  ///
  /// Examples:
  /// concat [[1, 2], [3], [4]]
  ///   = [1, 2, 3, 4]
  ///
  val <a> concat : List (List a) -> List a = foldr List::append Nil

  /// Maps a list-returning function over a list and concatenates the results.
  ///
  /// Examples:
  /// concatMap (\n -> [n, n+1, n+2]) [1, 2, 3]
  ///   = [1, 2, 3, 2, 3, 4, 3, 4, 5]
  ///
  val <a, b> concatMap : (a -> List b) -> List a -> List b =
    \f -> foldr (\x -> \acc -> List::append (f x) acc) Nil

  /// Reverses a list.
  ///
  /// Examples:
  /// reverse [1, 2, 3]
  ///   = [3, 2, 1]
  ///
  val <a> reverse : List a -> List a = foldl (\xs -> \x -> Cons x xs) Nil

  /// Given an integer, m, and a list, 'take' returns the first m elements of
  /// the list.  If the list has fewer than m elements, the whole list is
  /// returned.
  ///
  /// Examples:
  /// take 2 ["a", "b", "c"]
  ///   = ["a", "b"]
  ///
  /// take 2 ["a"]
  ///   = ["a"]
  ///
  val <a> take : Int -> List a -> List a = \(m : Int) -> \xs ->
    let val f = \x -> \rest -> \n ->
      if (n <= 0) Nil
      else Cons x (rest (n - 1))
    in foldr f (const Nil) xs m

  /// Given a predicate, p, and a list, 'takeWhile' takes the elements of the
  /// list as long as the predicate holds.
  ///
  /// Examples:
  /// takeWhile (const True) ["a", "b", "c"]
  ///   = ["a", "b", "c"]
  ///
  /// takeWhile (\x -> x > 5) [6, 9, 5, 4, 8]
  ///   = [6, 9]
  ///
  val <a> takeWhile : (a -> Bool) -> List a -> List a = \pred ->
    foldr (\el -> \acc -> if (pred el) (Cons el acc) else []) []

  /// Given an integer, m, and a list, 'drop' throws away the first m elements
  /// of the list, and returns the rest.  If the list has fewer than m elements,
  /// the empty list is returned.
  ///
  /// Examples:
  /// drop 2 ["a", "b", "c"]
  ///   = ["c"]
  ///
  /// drop 1 ["a"] = []
  ///
  /// drop 1 [] = []
  ///
  val <a> drop : Int -> List a -> List a =
    \(m : Int) -> \xs ->
      let val f = \_ -> \rest -> \n -> \xs1 ->
        if (n <= 0) xs1
        else rest (n - 1) (fromMaybe Nil (List::tail xs1))
      in foldr f (const (const Nil)) xs m xs
}

//////////////////////
// NonEmptyList
//////////////////////

module NonEmptyList {

  /// Turns a non-empty list into an ordinary list.
  ///
  /// Examples:
  ///
  /// toList (NonEmpty 1 []) = [1]
  /// toList (NonEmpty 1 [2, 3]) = [1, 2, 3]
  val <a> toList : NonEmptyList a -> List a = \NonEmpty x xs -> Cons x xs

  /// Converts a list into a non-empty list, if the given list is not empty.
  /// Otherwise it returns 'None'.
  ///
  /// Examples:
  ///
  /// fromList [] = None
  /// fromList [1, 2, 3] = Some (NonEmpty 1 [2, 3])
  val <a> fromList : List a -> Maybe (NonEmptyList a) =
    \ Nil -> None
    | Cons hd rest -> Some (NonEmpty hd rest)

  /// Creates a non-empty list with one element.
  ///
  /// Examples:
  ///
  /// singleton 5 = NonEmpty 5 []
  /// singleton "a" = NonEmpty "a" []
  val <a> singleton: a -> NonEmptyList a = \x -> NonEmpty x []

  /// Returns the head (i.e. the first element) of the non-empty list.
  ///
  /// Examples:
  ///
  /// head (NonEmpty 0 []) = 0
  /// head (NonEmpty 1 [2, 3]) = 1
  val <a> head : NonEmptyList a -> a = \NonEmpty x _ -> x

  /// Returns the tail of a non-empty list (i.e. what remains when stripping away the first element).
  ///
  /// Examples:
  ///
  /// tail (NonEmpty 0 []) = []
  /// tail (NonEmpty 1 [2, 3]) = [2, 3]
  val <a> tail : NonEmptyList a -> List a = \NonEmpty _ xs -> xs

  /// Returns the minimum of a non-empty list.
  /// Uses the ordering function provided as the first argument to compare elements.
  ///
  /// Examples:
  ///
  /// minimum compareInt (NonEmpty 0 []) = 0
  /// minimum compareInt (NonEmpty 1 [6, 0, 234, 2]) = 0
  val <a> minimum : (a -> a -> Ordering) -> NonEmptyList a -> a = \cmp -> \NonEmpty h _ as nel ->
    fromMaybe h (List::minimum cmp (toList nel))

  /// Returns the maximum of a non-empty list.
  /// Uses the ordering function provided as the first argument to compare elements.
  ///
  /// Examples:
  ///
  /// maximum compareInt (NonEmpty 0 []) = 0
  /// maximum compareInt (NonEmpty 1 [6, 0, 234, 2]) = 234
  val <a> maximum : (a -> a -> Ordering) -> NonEmptyList a -> a = \cmp -> \NonEmpty h _ as nel ->
    fromMaybe h (List::maximum cmp (toList nel))

  /// Returns 'True' if the non-emptylist contains the given value.
  /// Otherwise it returns 'False'.
  ///
  /// Examples:
  /// contains 5 (NonEmpty 0 []) = False
  /// contains 3.5 (NonEmpty 0.0 [3.5, 7.0]) = True
  ///
  val <a: Ord> contains : a -> NonEmptyList a -> Bool = \el -> comp (List::contains el) toList

  /// The 'sort' function takes an ordering function and a non-empty list,
  /// and returns an ordered non-empty list.
  ///
  /// Examples:
  /// sort compareInt (NonEmpty 4 [2, 3]) = NonEmpty 2 [3, 4]
  ///
  val <a> sort : (a -> a -> Ordering) -> NonEmptyList a -> NonEmptyList a = \ordering -> \NonEmpty hs _ as lst ->
    fromMaybe (NonEmpty hs []) (fromList (List::sort ordering (toList lst)))

  /// The 'isSorted' function takes an ordering function and a non-empty list,
  /// and returns True if the list is ordered. Otherwise, it returns 'False'.
  ///
  /// Examples:
  /// isSorted compareInt (NonEmpty 1 [3, 3, 6]) = True
  /// isSorted compareInt (NonEmpty 1 [6, 3]) = False
  ///
  val <a> isSorted : (a -> a -> Ordering) -> NonEmptyList a -> Bool = \ordering ->
    comp (List::isSorted ordering) toList

  /// The 'length' function returns the number of elements in a non-empty list.
  /// Examples:
  /// length (NonEmpty "a" ["b", "c"]) = 3
  /// length (NonEmpty 1 []) = 1
  ///
  val <a> length : NonEmptyList a -> Int = comp List::length toList

  /// 'map f xs' is the list obtained by applying the function f on each of the
  /// elements in the non-empty list 'xs'.
  ///
  /// Examples:
  /// map (\n -> n * 2) (NonEmpty 1 [2, 3]) = NonEmpty 2 [4, 6]
  ///
  val <a, b> map : (a -> b) -> NonEmptyList a -> NonEmptyList b =
    \f -> \NonEmpty x xs -> NonEmpty (f x) (List::map f xs)

  /// The 'zipWith' function is like 'map' for two-argument functions.  It takes
  /// a binary function and two non-empty lists as arguments, and returns a
  /// non-empty list resulting from applying the function pairwise on the
  /// elements of the lists.
  /// The resulting list always has the same length as the shortest input list.
  ///
  /// Examples:
  /// zipWith (\m -> \n -> m + n) (NonEmpty 4 [5]) (NonEmpty 10 [20]) = NonEmpty 14 [25]
  /// zipWith (\m -> \n -> m + n) (NonEmpty 4 [5]) (NonEmpty 10 []) = NonEmpty 14 []
  /// zipWith (\m -> \n -> m + n) (NonEmpty 4 []) (NonEmpty 10 [20]) = NonEmpty 14 []
  ///
  val <a, b, c> zipWith : (a -> b -> c) -> NonEmptyList a -> NonEmptyList b -> NonEmptyList c = \f ->
    \NonEmpty x xs -> \NonEmpty y ys -> NonEmpty (f x y) (List::zipWith f xs ys)

  /// The 'zip' function takes two non-empty lists as arguments, and returns a
  /// non-empty list of the elements pairwise together.
  /// The resulting list always has the same length as the shortest input list.
  ///
  /// Examples:
  /// zip (NonEmpty 1 [2]) (NonEmpty "a" ["b"]) = NonEmpty (1, "a") [(2, "b")]
  /// zip (NonEmpty 4 [5, 6]) (NonEmpty 10 [20, 30, 40]) = NonEmpty (4, 10) [(5, 20), (6, 30)]
  ///
  val <a, b> zip : NonEmptyList a -> NonEmptyList b -> NonEmptyList (Tuple a b) = zipWith (\a -> \b -> (a, b))

  /// Given a predicate and a non-empty list, 'any' returns 'True' if, and only if, there
  /// exists an element in the list which satisfies the predicate.
  ///
  /// Examples:
  /// any (\n -> n > 4) (NonEmpty 2 [10]) = True
  /// any (\n -> n > 4) (NonEmpty 2 [0]) = False
  ///
  val <a> any : (a -> Bool) -> NonEmptyList a -> Bool =
    \pred -> comp (List::any pred) toList

  /// Given a predicate and a non-empty list, 'all' returns 'True' if, and only if, all
  /// elements in the list satisfy the predicate.
  ///
  /// Examples:
  /// all (\n -> n > 4) (NonEmpty 5 [6]) = True
  /// all (\n -> n > 4) (NonEmpty 5 [3]) = False
  ///
  val <a> all : (a -> Bool) -> NonEmptyList a -> Bool =
    \pred -> comp (List::all pred) toList

  /// Returns the first element in the non-empty list which satisfies the predicate,
  /// if any.
  ///
  /// Examples:
  /// first (\n -> n > 4) (NonEmpty 3 [42, 100]) = Some 42
  /// first (\n -> n > 4) (NonEmpty 3 [2, 1]) = None
  ///
  val <a> first : (a -> Bool) -> NonEmptyList a -> Maybe a =
    \pred -> comp (List::first pred) toList

  /// Returns the last element in the non-empty list which satisfies the predicate,
  /// if any.
  ///
  /// Examples:
  /// last (\n -> n > 4) (NonEmpty 3 [42, 100]) = Some 100
  /// last (\n -> n > 4) (NonEmpty 3 [2, 1]) = None
  ///
  val <a> last : (a -> Bool) -> NonEmptyList a -> Maybe a =
     \pred -> comp (List::last pred) toList

  /// Adds a new element at the start of a non-empty list.
  ///
  /// Examples:
  /// cons "a" (NonEmpty "b" []) = NonEmpty "a" ["b"]
  ///
  val <a> cons : a -> NonEmptyList a -> NonEmptyList a = \x -> \ys -> NonEmpty x (toList ys)

  /// Appends two non-empty lists.
  ///
  /// Examples:
  /// append (NonEmpty "a" []) (NonEmpty "b" []) = NonEmpty "a" ["b"]
  /// append (NonEmpty "a" ["b", "c"]) (NonEmpty "d" []) = NonEmpty "a" ["b", "c", "d"]
  ///
  val <a> append : NonEmptyList a -> NonEmptyList a -> NonEmptyList a =
    \NonEmpty x xs -> \ys -> NonEmpty x (List::append xs (toList ys))

  /// Flattens a non-empty list of non-empty lists into one non-empty list.
  ///
  /// Examples:
  /// concat (NonEmpty (NonEmpty 1 [2]) [NonEmpty 3 [], NonEmpty 4 []]) = NonEmpty 1 [2, 3, 4]
  ///
  val <a> concat : NonEmptyList (NonEmptyList a) -> NonEmptyList a = \NonEmpty (NonEmpty x xs) ys ->
    NonEmpty x (List::concat (Cons xs (List::map toList ys)))

  /// Maps a non-empty-list-returning function over a non-empty list and concatenates the results.
  ///
  /// Examples:
  /// concatMap (\n -> NonEmpty n [n+1, n+2]) (NonEmpty 1 [2, 3]) = (NonEmpty 1 [2, 3, 2, 3, 4, 3, 4, 5])
  ///
  val <a, b> concatMap : (a -> NonEmptyList b) -> NonEmptyList a -> NonEmptyList b =
    \f -> \NonEmpty x xs ->
    (\NonEmpty fx fxs -> NonEmpty fx (List::append fxs (List::concatMap (comp toList f) xs))) (f x)

  /// Returns the final (i.e. last) element of a non-empty list.
  ///
  /// Examples:
  /// final (NonEmpty 1 [2, 3]) = 3
  ///
  val <a> final : NonEmptyList a -> a = \NonEmpty x xs -> fromMaybe x (List::last (const True) xs)

  /// Reverses a non-empty list.
  ///
  /// Examples:
  /// reverse (NonEmpty 1 [2, 3]) = NonEmpty 3 [2, 1]
  ///
  val <a> reverse : NonEmptyList a -> NonEmptyList a = \xs -> fromMaybe xs (fromList (List::reverse (toList xs)))

}

//////////////////////
// Map
//////////////////////

module Map {
    /// Returns a new empty map.
    ///
    val <k, v> empty : Map k v = prim__Map_empty

    /// Returns true iff the given map is empty.
    ///
    /// Example:
    ///
    ///   Map::isEmpty Map::empty = true
    val isEmpty = prim__Map_isEmpty

    /// Returns a new map that contains, in addition to the keys
    /// already present in the argument map, the given key/value.
    ///
    /// Examples:
    /// val noElms = Map::empty
    /// val oneElm = Map::insert 1 "One" noElms
    /// val twoElms = Map::insert 2 "Two" oneElm
    ///
    val <k : Ord, v> insert : k -> v -> Map k v -> Map k v = prim__Map_insert

    /// Fold over the key/value pairs in a map.
    ///
    val <k : Ord, v, a> fold : (k -> v -> a -> a) -> a -> Map k v -> a = prim__Map_fold

    /// The 'toList' function returns a list of tuples (key, value) of elements of the map.
    ///
    /// Example:
    ///
    /// Map::toList (Map::fromList [(1, "A"), (2, "B")]) = [(2, "B"), (1, "A")]
    ///
    val <k : Ord, v> toList : Map k v -> List (Tuple k v) = fold (\k -> \v -> Cons (k, v)) []

    /// Returns a new map with the given key removed.
    ///
    /// Examples:
    /// val myMap = Map::insert 1 "One" Map::empty
    /// val myEmptyMap = Map::remove 1 myMap
    /// //             = Map::empty
    /// val myMap2 = Map::remove 2 myMap
    /// //         = myMap
    ///
    val <k : Ord, v> remove : k -> Map k v -> Map k v = prim__Map_remove

    /// Returns the value at the given key, if the key is in the map.
    /// Otherwise it returns 'None'.
    ///
    /// Examples:
    /// val myMap = Map::insert 1 "One" Map::empty
    /// val oneVal = Map::lookup 1 myMap
    /// //         = Some "One"
    /// val twoVal = Map::lookup 2 myMap
    /// //         = None
    ///
    val <k : Ord, v> lookup : k -> Map k v -> Maybe v = prim__Map_lookup

    /// Returns the value at the given key, if the key is in the map.
    /// Otherwise returns the given default value.
    ///
    /// Examples:
    /// val myMap = Map::insert 1 "One" Map::empty
    /// val oneVal = Map::lookupOrDefault "Nothing" 1 myMap
    ///          = "One"
    /// val twoVal = Map::lookupOrDefault "Nothing" 2 myMap
    ///         = "Nothing"
    ///
    val <k : Ord, v> lookupOrDefault : v -> k -> Map k v -> v = \default -> \key -> \map ->
      fromMaybe default (lookup key map)

    /// Constructs a map that contains the elements in the given list.
    ///
    /// Examples:
    /// val prices = Map::fromList [("hammer", 10), ("saw", 12), ("axe", 15)]
    ///
    val <k : Ord, v> fromList : List (Tuple k v) -> Map k v = \theList ->
      let
        val auxFun : Map k v -> Tuple k v -> Map k v = \accMap -> \(key, value) ->
            Map::insert key value accMap
      in
        foldl auxFun Map::empty theList
}


//////////////////////
// Set
//////////////////////

module Set {
    /// Returns a new empty set.
    ///
    val <v> empty : Set v = prim__Set_empty

    /// Returns a new set that contains, in addition to the elements
    /// already present in the argument set, the given element.
    ///
    /// Examples:
    /// val emptySet = Set::empty
    /// val oneElm = Set::insert 1 emptySet
    /// val twoElms = Set::insert 2 oneElm
    ///
    val <v : Ord> insert : v -> Set v -> Set v = prim__Set_insert

    /// Returns a new set with the given element removed.
    ///
    /// Examples:
    /// val mySet = Set::insert 1 Set::empty
    /// val myEmptySet = Set::remove 1 mySet
    /// //             = Set::empty
    /// val mySet2 = Set::remove 2 mySet
    /// //         = mySet
    ///
    val <v : Ord> remove : v -> Set v -> Set v = prim__Set_remove

    /// Fold over the elements in a set.
    ///
    /// Examples:
    /// val sumElems = Set::fold (\x -> \sum -> x + sum) 0
    /// val s = sumElems (Set::fromList [1, 2, 3])
    /// //    = 6
    ///
    val <v : Ord, a> fold : (v -> a -> a) -> a -> Set v -> a = prim__Set_fold

    /// Returns 'True' if the set contains the given value.
    /// Otherwise it returns 'False'.
    ///
    /// Examples:
    /// val mySet = Set::insert 1 Set::empty
    /// val oneVal = Set::contains 1 mySet
    /// //         = True
    /// val twoVal = Set::contains 2 mySet
    /// //         = False
    ///
    val <v : Ord> contains : v -> Set v -> Bool = prim__Set_contains

    /// Take the union of two sets.
    ///
    /// Examples:
    /// val setA = Set::fromList [1, 2]
    /// val setB = Set::fromList [2, 3]
    /// val setC = Set::union setA setB
    /// //       = Set::fromList [1, 2, 3]
    ///
    val <v : Ord> union : Set v -> Set v -> Set v = Set::fold Set::insert

    /// Take the intersection of two sets.
    ///
    /// Examples:
    /// val setA = Set::fromList [1, 2]
    /// val setB = Set::fromList [2, 3]
    /// val setC = Set::intersection setA setB
    /// //       = Set::singleton 2
    ///
    val <v : Ord> intersection : Set v -> Set v -> Set v =
      \l -> \r -> Set::fold (\x -> \s ->
        if (Set::contains x r) Set::insert x s
        else s) Set::empty l

    /// Take the difference between two sets.
    ///
    /// Examples:
    /// val setA = Set::fromList [1, 2]
    /// val setB = Set::fromList [2, 3]
    /// val setC = Set::difference setA setB
    /// //       = Set::fromList [1]
    ///
    val <v : Ord> difference : Set v -> Set v -> Set v = Set::fold Set::remove

    /// Constructs a set with the elements in the given list.
    ///
    /// Examples:
    /// val prices = Set::fromList [10, 12, 15]
    ///
    val <v : Ord> fromList : List v -> Set v = foldl (flip Set::insert) Set::empty

    /// Constructs a singleton set with just one element.
    ///
    /// Examples:
    /// val s = Set::singleton 1
    /// //    = Set::fromList [1]
    ///
    val <v : Ord> singleton : v -> Set v = \x -> Set::fromList [x]

    /// Converts a set to a list.  The ordering is unspecified and may change.
    ///
    /// Examples:
    /// val l = [1, 2, 3, 1, 2]
    /// val l2 = Set::toList (Set::fromList l)
    /// //     = [1, 2, 3]
    ///
    val <v : Ord> toList : Set v -> List v = Set::fold Cons Nil

    /// Returns the size of a set.
    ///
    /// Examples:
    /// val a = Set::size Set::empty
    /// //    = 0
    /// val b = Set::size (Set::fromList [1, 1, 2])
    /// //    = 2
    ///
    val <v : Ord> size : Set v -> Int = Set::fold (\_ -> \x -> x + 1) 0
}

//////////////////////
// Period
//////////////////////

module Period {
  val components : Period -> Components = prim__Period_components

  val fromComponents : Components -> Period = prim__Period_fromComponents

  val from : Int -> Int -> Int -> Period = \(y : Int) -> \(m : Int) -> \(d : Int) ->
    Period::fromComponents (Period::Components { years = y, months = m, days = d })

  val between : Date -> Date -> Period = prim__Period_between

  val add : Period -> Period -> Period = prim__Period_add

  val negated : Period -> Period = prim__Period_negated
}

//////////////////////
// Duration
//////////////////////

module Duration {
  val components : Duration -> Components = prim__Duration_components

  val fromComponents : Components -> Duration = prim__Duration_fromComponents

  val from : Int -> Int -> Duration =
    \(secs : Int) -> \(millis : Int) ->
      Duration::fromComponents (Duration::Components { seconds = secs, milliseconds = millis })

  val fromMinutes : Int -> Duration = \(minutes : Int) -> Duration::from (minutes*60) 0
  val fromHours : Int -> Duration = \(hours : Int) -> Duration::from (hours * 60 * 60) 0
  val fromDays : Int -> Duration = \(days : Int) -> Duration::from (days * 24 * 60 * 60) 0

  val betweenInstants : Instant -> Instant -> Duration = prim__Duration_betweenInstants

  val betweenTimes : Time -> Time -> Duration = prim__Duration_betweenTimes

  val add : Duration -> Duration -> Duration = prim__Duration_add

  val negated : Duration -> Duration = prim__Duration_negated
}

//////////////////////
// Instant
//////////////////////

module Instant {
  val components : Instant -> Components = prim__Instant_components

  val fromComponents : Components -> Instant = prim__Instant_fromComponents

  val from : Int -> Int -> Instant = \(s : Int) -> \(ms : Int) ->
    Instant::fromComponents (Instant::Components { second = s, millisecond = ms })

  val addDuration : Duration -> Instant -> Instant = prim__Instant_addDuration

  val addSeconds : Int -> Instant -> Instant = \(secs : Int) ->
    Instant::addDuration (Duration::fromComponents (Duration::Components { seconds = secs, milliseconds = 0 }))

  val addDays : Int -> Instant -> Instant = \(days : Int) ->
    Instant::addSeconds (days * 24 * 60 * 60)
}


//////////////////////
// Year
//////////////////////

module Year {
  /// Maps a year to its representation as an integer.
  ///
  val toInt : Year -> Int = prim__Year_toInt

  /// Constructs a year from its integer representation.
  /// Valid range is -999999999 to 999999999.
  /// Year numbers outside this range results in an error.
  ///
  val fromInt : Int -> Year = prim__Year_fromInt

  /// Checks whether a year is a leap year.
  ///
  /// Examples:
  /// val leap2000 = Year::isLeapYear (Year::fromInt 2000)
  /// //           = True
  /// val leap2013 = Year::isLeapYear (Year::fromInt 2013)
  /// //           = False
  ///
  val isLeapYear : Year -> Bool = prim__Year_isLeapYear

  /// Returns the number of days in the given year.
  ///
  /// Examples:
  /// val days2000 = Year::length (Year::fromInt 2000)
  /// //           = 366
  /// val days2013 = Year::length (Year::fromInt 2013)
  /// //           = 365
  ///
  val length : Year -> Int = \(y : Year) -> if (Year::isLeapYear y) 366 else 365
}

//////////////////////
// Month
//////////////////////

module Month {
  val toInt : Month -> Int =
    \ January -> 1
    | February -> 2
    | March -> 3
    | April -> 4
    | May -> 5
    | June -> 6
    | July -> 7
    | August -> 8
    | September -> 9
    | October -> 10
    | November -> 11
    | December -> 12

  val firstDayOfMonth : Bool -> Month -> Int = \(isLeap : Bool) ->
    let val leap = if (isLeap) 1 else 0 in
    \ January -> 1
    | February -> 32
    | March -> 60 + leap
    | April -> 91 + leap
    | May -> 121 + leap
    | June -> 152 + leap
    | July -> 182 + leap
    | August -> 213 + leap
    | September -> 244 + leap
    | October -> 274 + leap
    | November -> 305 + leap
    | December -> 335 + leap

  val firstMonthOfQuarter : Month -> Month =
      \ January -> January
      | February -> January
      | March -> January
      | April -> April
      | May -> April
      | June -> April
      | July -> July
      | August -> July
      | September -> July
      | October -> October
      | November -> October
      | December -> October
}

//////////////////////
// YearMonth
//////////////////////

module YearMonth {
  val components : YearMonth -> Components = prim__YearMonth_components

  val fromComponents : Components -> YearMonth = prim__YearMonth_fromComponents

  val from : Int -> Month -> YearMonth =
    \(y : Int) -> \(m : Month) ->
      YearMonth::fromComponents (YearMonth::Components { year = Year::fromInt y, month = m })

  val lengthOfMonth : YearMonth -> Int = prim__YearMonth_lengthOfMonth

  val isValidDay : Int -> YearMonth -> Bool =
    \(day : Int) -> \(ym : YearMonth) ->
      1 <= day && day <= YearMonth::lengthOfMonth ym
}

//////////////////////
// Date
//////////////////////

module Date {
  val components : Date -> Components = prim__Date_components

  val fromComponents : Components -> Date = prim__Date_fromComponents

  val from : Int -> Month -> Int -> Date = \(y : Int) -> \(m : Month) -> \(d : Int) ->
    Date::fromComponents (Date::Components { year = Year::fromInt y, month = m, day = d })

  val epochDay : Date -> Int = prim__Date_epochDay

  val dayOfWeek : Date -> DayOfWeek = prim__Date_dayOfWeek

  val addPeriod : Period -> Date -> Date = prim__Date_addPeriod
}

//////////////////////
// Time
//////////////////////

module Time {
  val components : Time -> Components = prim__Time_components

  val fromComponents : Components -> Time = prim__Time_fromComponents

  val from : Int -> Int -> Int -> Int -> Time =
    \(h : Int) -> \(m : Int) -> \(s : Int) -> \(ms : Int) ->
      Time::fromComponents (Time::Components { hour = h, minute = m, second = s, millisecond = ms })

  val addDuration : Duration -> Time -> Time = prim__Time_addDuration
}

//////////////////////
// DateTime
//////////////////////

type DateTime {
  date : Date,
  time : Time
}

module DateTime {
  val addPeriod : Period -> DateTime -> DateTime = \(p : Period) -> \(dt : DateTime) ->
    DateTime { use dt with date = Date::addPeriod p dt.date }
}

//////////////////////
// ZonedDateTime
//////////////////////

module ZonedDateTime {
  val components : ZonedDateTime -> ComponentsWithOffset = prim__ZonedDateTime_components

  val fromComponents : Components -> ZonedDateTime = prim__ZonedDateTime_fromComponents

  val fromComponentsWithOffset : ComponentsWithOffset -> ZonedDateTime = prim__ZonedDateTime_fromComponentsWithOffset

  val from : Date -> Time -> String -> ZonedDateTime =
    \(d : Date) -> \(t : Time) -> \(z : String) ->
      ZonedDateTime::fromComponents (ZonedDateTime::Components { date = d, time = t, zone = z })

  val fromStrict : Date -> Time -> String -> ZoneOffset -> ZonedDateTime =
    \(d : Date) -> \(t : Time) -> \(z : String) -> \(zo : ZoneOffset) ->
      ZonedDateTime::fromComponentsWithOffset
        (ZonedDateTime::ComponentsWithOffset
        { date = d
        , time = t
        , zone = z
        , offset = zo
        })

  val fromInstant : Instant -> String -> ZonedDateTime = prim__ZonedDateTime_fromInstant

  val withEarlierOffsetAtOverlap : ZonedDateTime -> ZonedDateTime = prim__ZonedDateTime_withEarlierOffsetAtOverlap

  val withLaterOffsetAtOverlap : ZonedDateTime -> ZonedDateTime = prim__ZonedDateTime_withLaterOffsetAtOverlap

  val addPeriod : Period -> ZonedDateTime -> ZonedDateTime = prim__ZonedDateTime_addPeriod

  val addDuration : Duration -> ZonedDateTime -> ZonedDateTime = prim__ZonedDateTime_addDuration

  val instant : ZonedDateTime -> Instant = prim__ZonedDateTime_instant
}

//////////////////////
// ZoneOffset
//////////////////////

module ZoneOffset {
  val fromSeconds : Int -> ZoneOffset = prim__ZoneOffset_fromSeconds

  val toSeconds : ZoneOffset -> Int = prim__ZoneOffset_toSeconds
}

//////////////////////
// DayCount
//////////////////////

module DayCount {
  val yearFraction : YearFraction -> Float = prim__yearFraction
}

//////////////////////
// Int
//////////////////////

module Int {
  /// Converts an `Int` to a `Float`.
  ///
  /// Examples:
  ///
  /// Int::toFloat 4 = 4.0
  ///
  val toFloat : Int -> Float = prim__Int_toFloat

  /// Converts an `Int` to a `String`.
  ///
  /// Examples:
  ///
  /// Int::toString 4 = "4"
  ///
  val toString : Int -> String = prim__Int_toString
}


//////////////////////
// Float
//////////////////////

module Float {
  /// Converts a `Float` to an `Int`.
  ///
  /// Examples:
  ///
  /// Float::toInt 4.0 = 4
  /// Float::toInt 1234.5678 = 1234
  /// Float::toInt -1234.5678 = -1234
  ///
  val toInt : Float -> Int = prim__Float_toInt
}


//////////////////////
// String
//////////////////////

module String {
  /// Appends two string.
  ///
  /// Examples:
  ///
  /// String::append "Hello, " "World!" = "Hello, World!"
  ///
  val append : String -> String -> String = prim__String_append

  /// 'isEmpty' returns True if a string is the empty string. False otherwise.
  ///
  /// Examples
  /// String::isEmpty "" = True
  /// String::isEmpty "abc" = False
  ///
  val isEmpty = \(s: String) -> s = ""
}

//////////////////////
// Bool, continued
//////////////////////

/// The `equal` function returns 'True' if the two elements provided to it are equal, and 'False' otherwise.
///
/// Examples:
/// equal 5 6 = False
/// equal (3.14, 5) (3.14, 2 + 3) = True
///
val <a: Ord> equal : a -> a -> Bool = \x -> \y -> Set::contains x (Set::fromList [y])

//////////////////////
// Mathematical functions
//////////////////////

module Math {
  /// Get the absolute value of an 'Int'.
  val abs : Int -> Int = \x -> if (x < 0) 0 - x else x

  /// Get the absolute value of a 'Float'.
  val fabs : Float -> Float = \x -> if (x < 0.0) 0.0 - x else x

  /// The power function.
  ///
  /// Examples:
  ///
  /// Math::pow 4.0 3.0 = 64.0
  ///
  val pow : Float -> Float -> Float = prim__Math_pow

  /// Square root.
  ///
  /// Examples:
  ///
  /// Math::sqrt 9.0 = 3.0
  ///
  val sqrt : Float -> Float = \x -> Math::pow x 0.5

  /// Rounds the number to an arbitrary decimal point using the given rounding mode
  ///
  /// Examples:
  ///
  /// Math::round 123.45 1 HalfUp ==> 123.5
  ///
  val round : Float -> Int -> RoundingMode -> Float = prim__Math_round

  /// Rounds the number towards positive infinity.
  ///
  /// Examples:
  ///
  /// Math::ceiling 1.3 = 2.0
  /// Math::ceiling -1.3 = -1.0
  ///
  val ceiling : Float -> Float = \x -> Math::round x 0 Ceiling

  /// Rounds the number towards negative infinity.
  ///
  /// Examples:
  ///
  /// Math::floor 1.8 = 1.0
  /// Math::floor -1.8 = -2.0
  ///
  val floor : Float -> Float = \x -> Math::round x 0 Floor
}


//////////////////////
// Signed data
//////////////////////

module Signed {
  /// Check if a 'Signed' is signed by a given 'PublicKey'
  val <a> checkSignature : PublicKey -> Signed a -> Bool = prim__Signed_checkSignature

  /// Extract the message contained within a 'Signed'
  val <a> message : Signed a -> a = prim__Signed_message
}

//////////////////////
// Testing
//////////////////////

module Test {
  /// A unit test assertion that always passes
  val pass : UnitTest = prim__Test_pass

  /// A unit test assertion that always fails. The argument is used as
  /// the assertion failure message.
  val <a> fail : a -> UnitTest = prim__Test_fail

  /// A unit test assertion that always fails. The first argument is
  /// presented as the expected value, and the second argument is
  /// presented as what was actually found.
  val <a, b> expected : a -> b -> UnitTest = prim__Test_expected

  /// Run a unit test as part of a test suite. The provided string is
  /// the test name, used in printed reports and in development tools.
  val unitTest : String -> (Unit -> UnitTest) -> Test = prim__Test_unitTest

  /// Group tests together into a named suite. This does not affect
  /// whether they pass or fail, but it can make the results of
  /// running many tests easier to understand. The first argument is
  /// the name of the test suite.
  val suite : String -> List Test -> Test = prim__Test_suite

  /// Contstruct a test based on some external data provided by the
  /// testing system. The first argument is a key used to select the
  /// appropriate external data source, and the second is a function
  /// that builds a test from the found data.
  ///
  /// Beware: if the external data doesn't have the type expected by
  /// the testing function, then CSL will crash while running tests!
  val <a> withData : String -> (a -> Test) -> Test = prim__Test_withData

  /// Given a data source name that provides a list of test data, use
  /// the provided test construction function to transform each test
  /// datum into a unit test name and a unit test. The resulting test
  /// suite runs one test for each item of input data and is named
  /// identically to the test data source.
  val <a> suiteWithData : String -> (a -> Tuple String (Unit -> UnitTest)) -> Test =
    \name -> \testCase ->
       withData name \cases ->
         suite name
           (List::map (\data -> let val (subName, body) = testCase data in unitTest subName body) cases)

  /// Assert that some condition is true. If not, the test fails.
  val assert : Bool -> UnitTest =
    \ True -> pass
    | False -> fail "Assertion failed"

  /// Assert that some condition is false. If not, the test fails.
  val assertFalse = \b -> Test::assert (not b)

  /// Assert that two values are equal. If then are not, then the
  /// first one is reported as the expected value, and the second is
  /// reported as the received value.
  val <a: Ord> assertEqual : a -> a -> UnitTest =
    \wanted -> \got ->
      (\True -> pass | False -> expected wanted got)
      (equal wanted got)

  /// Use a custom predicate to assert the equality of two values. If
  /// the assertion fails, then the first value is presented as the
  /// desired value, while the second is presented as the received
  /// value.
  val <a, b> assertEqualBy : (a -> b -> Bool) -> a -> b -> UnitTest =
    \predicate -> \wanted -> \got ->
      (\True -> pass | False -> expected wanted got)
      (predicate wanted got)

  /// Assert that the difference between two floats is less than 0.0000001.
  val assertEqualEpsilon : Float -> Float -> UnitTest =
    \wanted -> \got ->
      assertEqualBy (\(x : Float) -> \y -> Math::fabs (x - y) < 0.0000001)
        wanted
        got

  /// Run a test with a freshly-constructed agent. The provided string
  /// is used in two ways: it names the agent internally, which can
  /// lead to better test failure messages in many CSL backends, and
  /// multiple invocations with the same string will result in the
  /// same agent.
  val withAgent : String -> (Agent -> Test) -> Test = prim__Test_withAgent

  /// Run a test with a pair of freshly-constructed agents. The
  /// provided strings are used in two ways: they name the agents
  /// internally, which can lead to better test failure messages in
  /// many CSL backends, and multiple invocations with the same strings
  /// will result in the same agents.
  val with2Agents : Tuple String String -> (Tuple Agent Agent -> Test) -> Test =
    \(name1, name2) -> \f ->
      withAgent name1 \agent1 -> withAgent name2 \agent2 ->
        f (agent1, agent2)

  /// Run a scenario test under a given name.
  val runScenario : String -> Scenario -> Test = prim__Test_runScenario
}

// For now we use a String for the denotation of the observable.
external <a, b> prim__Scenario_observation : String -> a -> b -> Scenario::Step

module Scenario {
  /// Apply an event to the current contract. If the event cannot be
  /// applied, the scenario test fails.
  val event : Event -> Scenario::Step = prim__Scenario_event

  /// Add a new observation-value for the given observable source at the given input
  val observation = prim__Scenario_observation

  /// Assert that the contract is fulfilled, meaning that it is
  /// considered acceptable if no more events occur. Note that this
  /// does not rule out further events - they are optional.
  val isFulfilled : Scenario::Step = prim__Scenario_isFulfilled

  /// Assert that the contract is not fulfilled, meaning that further
  /// events are mandatory.
  val isNotFulfilled : Scenario::Step = prim__Scenario_isNotFulfilled

  /// Run a sequence of scenario steps in order.
  val steps : List Scenario::Step -> Scenario::Step = prim__Scenario_steps

  // Run the given scenario step. If it succeeds, the contract under
  // test has its state rolled back as if the step had never
  // occurred. If it fails, then the test fails.
  val withRollback : Scenario::Step -> Scenario::Step = prim__Scenario_withRollback

  // Run the given scenario step. If it fails, then the contract under
  // test has its state rolled back as if the step had never
  // occurred. If it succeeds, then the test fails with the provided
  // message.
  val expectFailure : String -> Scenario::Step -> Scenario::Step = prim__Scenario_expectFailure

  /// Compute a scenario step from the list of events that have been applied thus far.
  val withHistory : (List Event -> Scenario::Step) -> Scenario::Step = prim__Scenario_withHistory

  /// Run a unit test assertion as part of a scenario test.
  val unitTest : String -> (Unit -> UnitTest) -> Scenario::Step =  prim__Scenario_unitTest

  /// Assert that the history of events thus far satisfies some
  /// condition. If not, the scenario test fails with the provided
  /// message.
  val eventsSatisfy : String -> (List Event -> Bool) -> Scenario::Step = \message -> \predicate ->
    withHistory \events ->
      unitTest message \() ->
        if (predicate events)
          Test::pass
        else
          Test::fail message

  /// Assert that an event can be applied without applying it.
  val canApplyEvent : Event -> Scenario::Step = \e ->
    withRollback (event e)

  /// Assert that an event cannot be applied.
  val cannotApplyEvent : Event -> Scenario::Step = \e ->
    withRollback (expectFailure "Cannot apply event" (event e))
}