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 : 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
///
/// headOrDefault : a -> List a -> a

/// 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)
}

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

module DateTime {
/// addSeconds : DateTime -> Int -> DateTime

/// 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

/// dayCountFraction : DateTime::DayCountFraction -> DateTime -> DateTime -> Float
val dayCountFraction = prim__dayCountFraction
}

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

module Duration {

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

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

/// addSeconds : DateTime -> Float -> DateTime

/// 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

/// 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) ->

/// 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
}

//////////////////////
// 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
}