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"
///
/// id : a -> a
val id = \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"
///
/// const : a -> b -> a
val const = \x -> \_ -> x

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


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

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


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

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

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


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

type Maybe a
  | None
  | Some a

/// 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
///
/// maybe : b -> (a -> b) -> Maybe a -> b
val maybe = \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 fromMaybe = 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
  ///
  /// map : (a -> b) -> Maybe a -> Maybe b
  val map = \f ->
    \ None -> None
    | Some x -> Some (f x)

  /// Returns 'True' if the input is a 'Some', returns 'False' otherwise.
  ///
  /// Examples:
  /// isSome (Some 2) = True
  /// isSome None = False
  ///
  /// isSome : Maybe a -> Bool
  val isSome =
    \ 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
  ///
  /// any : (a -> Bool) -> Maybe a -> Bool
  val any = \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
  ///
  /// all : (a -> Bool) -> Maybe a -> Bool
  val all = \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
  ///
  /// bind : (a -> Maybe b) -> Maybe a -> Maybe b
  val bind = \f ->
    \ None -> None
    | Some x -> f x

}


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

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

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

/// compareDateTime : DateTime -> DateTime -> Ordering
val compareDateTime = \(x : DateTime) -> \y ->
  if (x < y) Less else if (x = y) Equal else Greater


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

// forall a b . (b -> a -> b) -> b -> List a -> b
val foldl = prim__foldl
// forall a b . (a -> b -> b) -> b -> List a -> b
val foldr = 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
  ///
  /// head : List a -> Maybe a
  val head =
    \ 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
  ///
  /// headOrDefault : a -> List a -> a
  val headOrDefault = \default -> \xs -> fromMaybe default (List::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
  ///
  /// tail : List a -> Maybe a
  val tail =
    \ Nil -> None
    | Cons _ xs -> Some xs

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

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

  /// 'isEmpty' returns True if a list is empty. False otherwise.
  ///
  /// Examples
  /// isEmpty [1, 2, 3]
  ///    = False
  ///
  /// List a -> Boolean
  val isEmpty =
    \ 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]
  ///
  /// map : (a -> b) -> List a -> List b
  val map = \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"]
  ///
  /// mapMaybe : (a -> Maybe b) -> List a -> List b
  val mapMaybe = \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]
  /// filter : (a -> Bool) -> List a -> List a
  val filter = \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]
  ///
  /// zipWith : (a -> b -> c) -> List a -> List b -> List c
  val zipWith = \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)]
  ///
  /// zip : List a -> List b -> List (Tuple a b)
  val zip = 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
  ///
  /// any : (a -> Bool) -> List a -> Bool
  val any = \pred -> foldl (\b -> \x -> pred x || b) 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
  /// all : (a -> Bool) -> List a -> Bool
  val all = \pred -> foldl (\b -> \x -> pred x && b) 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
  ///
  /// first : (a -> Bool) -> List a -> Maybe a
  val first = \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
  ///
  /// last : (a -> Bool) -> List a -> Maybe a
  val last = \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
  ///
  /// append : List a -> List a -> List a
  val append = \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]
  ///
  /// concat : List (List a) -> List a
  val concat = 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]
  ///
  /// concatMap : (a -> List b) -> List a -> List b
  val concatMap = \f -> foldr (\x -> \acc -> List::append (f x) acc) Nil

  /// Reverses a list.
  ///
  /// Examples:
  /// reverse [1, 2, 3]
  ///   = [3, 2, 1]
  ///
  /// reverse : List a -> List a
  val reverse = 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"]
  ///
  /// take : Int -> List a -> List a
  val take = \(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 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 [] = []
  ///
  /// drop : Int -> List a -> List a
  val drop = \(m : Int) -> \xs ->
    let val f = \x -> \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

  /// Given an equality relation and two lists, `equalsWith` returns `True` if, and only
  /// if, all the pairwise matched elements of the lists satisfy the given relation, and
  /// the two lists are of equal lengths.
  ///
  /// This can be used to used to compare structural equality of lists.
  ///
  /// Examples:
  /// equalsWith (\(m : Int) -> \n -> m = n) [1] [1]
  ///   = True
  ///
  /// equalsWith (\(m : Int) -> \n -> m = n) [1] [2]
  ///   = False
  ///
  /// equalsWith (\(m : Int) -> \n -> m = n) [1] []
  ///   = False
  ///
  /// equalsWith : (a -> b -> Bool) -> List a -> List b -> Bool
  val equalsWith = \rel ->
    let
      val firstIsCons = \a -> \g ->
        \ Nil -> False
        | Cons b bs -> rel a b && g bs
      val firstIsNil =
        \ Nil -> True
        | Cons _ _ -> False
    in foldr firstIsCons firstIsNil
    // the above is equivalent to, but asymptotically faster than:
    // \xs -> \ys -> (List::length xs = List::length ys) && List::all id (List::zipWith rel xs ys)

  module Int {
    /// Structural equality relation for List Int.
    ///
    /// Examples:
    /// equals [1] [1]
    ///   = True
    ///
    /// equals [1] [2]
    ///   = False
    ///
    /// equals [1] []
    ///   = False
    ///
    /// equals : List Int -> List Int -> Bool
    val equals = List::equalsWith (\(x : Int) -> \y -> x = y)
  }

  module Float {
    /// Structural equality relation for List Float.
    ///
    /// Examples:
    /// equals [1.0] [1.0]
    ///   = True
    ///
    /// equals [1.0] [2.0]
    ///   = False
    ///
    /// equals [1.0] []
    ///   = False
    ///
    /// equals : List Float -> List Float -> Bool
    val equals = List::equalsWith (\(x : Float) -> \y -> x = y)
  }

  module String {
    /// Structural equality relation for List String.
    ///
    /// Examples:
    /// equals ["foo"] ["foo"]
    ///   = True
    ///
    /// equals ["foo"] ["bar"]
    ///   = False
    ///
    /// equals ["foo"] []
    ///   = False
    ///
    /// equals : List String -> List String -> Bool
    val equals = List::equalsWith (\(x : String) -> \y -> x = y)
  }

  module DateTime {
    /// Structural equality relation for List DateTime.
    ///
    /// Examples:
    /// equals [#2018-02-08T10:00:00Z#] [#2018-02-08T10:00:00Z#]
    ///   = True
    ///
    /// equals [#2018-02-08T10:00:00Z#] [#2017-12-24T12:00:00Z#]
    ///   = False
    ///
    /// equals [#2018-02-08T10:00:00Z#] []
    ///   = False
    ///
    /// equals : List DateTime -> List DateTime -> Bool
    val equals = List::equalsWith (\(x : DateTime) -> \y -> x = y)
  }
}


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

module DateTime {
  /// addSeconds : DateTime -> Int -> DateTime
  val addSeconds = prim__DateTime_addSeconds

  /// addDays : DateTime -> Int -> DateTime
  val addDays = \(d : DateTime) -> \(days : Int) ->
    DateTime::addSeconds d (days * 24 * 60 * 60)

  /// components : DateTime -> DateTime::Components
  val components = prim__DateTime_components

  /// dayOfWeek : DateTime -> DateTime::DayOfWeek
  val dayOfWeek = prim__DateTime_dayOfWeek
}

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

module Duration {

  /// fromSeconds : Float -> Duration
  val fromSeconds = prim__Duration_fromSeconds

  /// toSeconds : Duration -> Float
  val toSeconds = prim__Duration_toSeconds

  /// addSeconds : DateTime -> Float -> DateTime
  val addSeconds = prim__Duration_addSeconds

  /// diffDateTimes : DateTime -> DateTime -> Duration
  val diffDateTimes = prim__Duration_diffDateTimes

  /// between : DateTime -> DateTime -> Duration
  val between = flip Duration::diffDateTimes

  /// fromMinutes : Float -> Duration
  val fromMinutes = \(x : Float) -> Duration::fromSeconds (x * 60.0)

  /// fromHours : Float -> Duration
  val fromHours = \(x : Float) -> Duration::fromMinutes (x * 60.0)

  /// fromDays : Float -> Duration
  val fromDays = \(x : Float) -> Duration::fromHours (x * 24.0)

  /// addDurations : Duration -> Duration -> Duration
  val addDurations = prim__Duration_addDurations

  /// subDurations : Duration -> Duration -> Duration
  val subDurations = \(x : Duration) -> \(y : Duration) ->
    Duration::fromSeconds (Duration::toSeconds x - Duration::toSeconds y)

  /// addToDateTime : DateTime -> Duration -> DateTime
  val addToDateTime = \(dt : DateTime) -> \(dur : Duration) ->
    Duration::addSeconds dt (Duration::toSeconds dur)

  /// negate : Duration -> Duration -> Duration
  val negate = \(d : Duration) -> Duration::fromSeconds (-1.0 * (Duration::toSeconds d))

  /// components : Duration -> Duration::Components
  val components = prim__Duration_components

}


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

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

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


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

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


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

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

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

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

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


//////////////////////
// Events
//////////////////////

// ContractId -> List Event
val getEvents = prim__getEvents

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

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

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