new approach for defining our builtins

This commit is contained in:
Folkert 2022-07-08 02:51:04 +02:00
parent 98c55ba30c
commit 41768bfa97
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
11 changed files with 450 additions and 8 deletions

View file

@ -68,14 +68,27 @@ interface Dict
## `fn dict1 == fn dict2` also being `True`, even if `fn` relies on the dictionary's ordering.
## An empty dictionary.
empty : Dict k v
single : k, v -> Dict k v
get : Dict k v, k -> Result v [KeyNotFound]*
get = \dict, key ->
result = getLowlevel dict key
when result.flag is
True -> Ok result.value
False -> Err KeyNotFound
getLowlevel : Dict k v, k -> { flag : Bool, value : v }
walk : Dict k v, state, (state, k, v -> state) -> state
insert : Dict k v, k, v -> Dict k v
len : Dict k v -> Nat
remove : Dict k v, k -> Dict k v
contains : Dict k v, k -> Bool
single : k, v -> Dict k v
single = \key, value ->
Dict.empty
|> Dict.insert key value
## Returns a [List] of the dictionary's keys.
keys : Dict k v -> List k

View file

@ -717,6 +717,10 @@ takeLast = \list, outputLength ->
## Drops n elements from the beginning of the list.
drop : List elem, Nat -> List elem
drop = \list, n ->
remaining = Num.subSaturated (List.len list) n
List.takeLast list remaining
## Drops the element at the given index from the list.
##
@ -835,6 +839,13 @@ intersperse = \list, sep ->
## means if you give an index of 0, the `before` list will be empty and the
## `others` list will have the same elements as the original list.)
split : List elem, Nat -> { before : List elem, others : List elem }
split = \elements, userSplitIndex ->
length = List.len elements
splitIndex = if length > userSplitIndex then userSplitIndex else length
before = List.sublist elements { start: 0, len: splitIndex }
others = List.sublist elements { start: splitIndex, len: length - splitIndex }
{ before, others }
## Primitive for iterating over a List, being able to decide at every element whether to continue
iterate : List elem, s, (s, elem -> [Continue s, Break b]) -> [Continue s, Break b]

View file

@ -509,8 +509,28 @@ Dec : Num (FloatingPoint Decimal)
toStr : Num * -> Str
intCast : Int a -> Int b
bytesToU16Lowlevel : List U8, Nat -> U16
bytesToU32Lowlevel : List U8, Nat -> U32
bytesToU16 : List U8, Nat -> Result U16 [OutOfBounds]
bytesToU16 = \bytes, index ->
# we need at least 1 more byte
offset = 1
if index + offset < List.len bytes then
Ok (bytesToU16Lowlevel bytes index)
else
Err OutOfBounds
bytesToU32 : List U8, Nat -> Result U32 [OutOfBounds]
bytesToU32 = \bytes, index ->
# we need at least 3 more bytes
offset = 3
if index + offset < List.len bytes then
Ok (bytesToU32Lowlevel bytes index)
else
Err OutOfBounds
compare : Num a, Num a -> [LT, EQ, GT]
@ -554,22 +574,27 @@ isGte : Num a, Num a -> Bool
## Returns `True` if the number is `0`, and `False` otherwise.
isZero : Num a -> Bool
isZero = \x -> x == 0
## A number is even if dividing it by 2 gives a remainder of 0.
##
## Examples of even numbers: 0, 2, 4, 6, 8, -2, -4, -6, -8
isEven : Int a -> Bool
isEven = \x -> Num.isMultipleOf x 2
## A number is odd if dividing it by 2 gives a remainder of 1.
##
## Examples of odd numbers: 1, 3, 5, 7, -1, -3, -5, -7
isOdd : Int a -> Bool
isOdd = \x -> Bool.not (Num.isMultipleOf x 2)
## Positive numbers are greater than `0`.
isPositive : Num a -> Bool
isPositive = \x -> x > 0
## Negative numbers are less than `0`.
isNegative : Num a -> Bool
isNegative = \x -> x < 0
toFrac : Num * -> Frac *
@ -682,7 +707,11 @@ mul : Num a, Num a -> Num a
sin : Frac a -> Frac a
cos : Frac a -> Frac a
tan : Frac a -> Frac a
tan = \x ->
# `tan` is not available as an intrinsic in LLVM
Num.div (Num.sin x) (Num.cos x)
asin : Frac a -> Frac a
acos : Frac a -> Frac a
@ -713,9 +742,22 @@ atan : Frac a -> Frac a
##
## >>> Num.sqrt -4.0f64
sqrt : Frac a -> Frac a
sqrtChecked : Frac a -> Result (Frac a) [SqrtOfNegative]*
sqrtChecked = \x ->
if x < 0.0 then
Err SqrtOfNegative
else
Ok (Num.sqrt x)
log : Frac a -> Frac a
logChecked : Frac a -> Result (Frac a) [LogNeedsPositive]*
logChecked = \x ->
if x <= 0.0 then
Err LogNeedsPositive
else
Ok (Num.log x)
## Divide one [Frac] by another.
##
@ -748,9 +790,22 @@ logChecked : Frac a -> Result (Frac a) [LogNeedsPositive]*
## >>> Num.pi
## >>> |> Num.div 2.0
div : Frac a, Frac a -> Frac a
divChecked : Frac a, Frac a -> Result (Frac a) [DivByZero]*
divChecked = \a, b ->
if b == 0 then
Err DivByZero
else
Ok (Num.div a b)
divCeil : Int a, Int a -> Int a
divCeilChecked : Int a, Int a -> Result (Int a) [DivByZero]*
divCeilChecked = \a, b ->
if b == 0 then
Err DivByZero
else
Ok (Num.divCeil a b)
## Divide two integers, truncating the result towards zero.
##
@ -769,7 +824,13 @@ divCeilChecked : Int a, Int a -> Result (Int a) [DivByZero]*
## >>> Num.divTrunc 8 -3
##
divTrunc : Int a, Int a -> Int a
divTruncChecked : Int a, Int a -> Result (Int a) [DivByZero]*
divTruncChecked = \a, b ->
if b == 0 then
Err DivByZero
else
Ok (Num.divTrunc a b)
## Obtain the remainder (truncating modulo) from the division of two integers.
##
@ -783,7 +844,13 @@ divTruncChecked : Int a, Int a -> Result (Int a) [DivByZero]*
##
## >>> Num.rem -8 -3
rem : Int a, Int a -> Int a
remChecked : Int a, Int a -> Result (Int a) [DivByZero]*
remChecked = \a, b ->
if b == 0 then
Err DivByZero
else
Ok (Num.rem a b)
isMultipleOf : Int a, Int a -> Bool
@ -842,6 +909,15 @@ addSaturated : Num a, Num a -> Num a
## This is the same as [Num.add] except if the operation overflows, instead of
## panicking or returning ∞ or -∞, it will return `Err Overflow`.
addChecked : Num a, Num a -> Result (Num a) [Overflow]*
addChecked = \a, b ->
result = addCheckedLowlevel a b
if result.b then
Err Overflow
else
Ok result.a
addCheckedLowlevel : Num a, Num a -> {b: Bool, a : Num a}
subWrap : Int range, Int range -> Int range
@ -859,6 +935,15 @@ subSaturated : Num a, Num a -> Num a
## This is the same as [Num.sub] except if the operation overflows, instead of
## panicking or returning ∞ or -∞, it will return `Err Overflow`.
subChecked : Num a, Num a -> Result (Num a) [Overflow]*
subChecked = \a, b ->
result = subCheckedLowlevel a b
if result.b then
Err Overflow
else
Ok result.a
subCheckedLowlevel : Num a, Num a -> {b: Bool, a : Num a}
mulWrap : Int range, Int range -> Int range
@ -874,6 +959,15 @@ mulSaturated : Num a, Num a -> Num a
## This is the same as [Num.mul] except if the operation overflows, instead of
## panicking or returning ∞ or -∞, it will return `Err Overflow`.
mulChecked : Num a, Num a -> Result (Num a) [Overflow]*
mulChecked = \a, b ->
result = mulCheckedLowlevel a b
if result.b then
Err Overflow
else
Ok result.a
mulCheckedLowlevel : Num a, Num a -> {b: Bool, a : Num a}
## The lowest number that can be stored in an [I8] without underflowing its
## available memory and crashing.

View file

@ -24,10 +24,19 @@ single : k -> Set k
## retrieved or removed from the [Set].
insert : Set k, k -> Set k
len : Set k -> Nat
len = \set ->
set
|> Set.toDict
|> Dict.len
## Drops the given element from the set.
remove : Set k, k -> Set k
contains : Set k, k -> Bool
contains = \set, key ->
set
|> Set.toDict
|> Dict.contains key
# toList = \set -> Dict.keys (toDict set)
toList : Set k -> List k

View file

@ -202,7 +202,36 @@ toUtf8 : Str -> List U8
# fromUtf8 : List U8 -> Result Str [BadUtf8 Utf8Problem]*
# fromUtf8Range : List U8 -> Result Str [BadUtf8 Utf8Problem Nat, OutOfBounds]*
fromUtf8 : List U8 -> Result Str [BadUtf8 Utf8ByteProblem Nat]*
fromUtf8 = \bytes ->
result = fromUtf8RangeLowlevel bytes { start: 0, count: List.len bytes }
if result.cIsOk then
Ok result.bString
else
Err (BadUtf8 result.dProblemCode result.aByteIndex)
fromUtf8Range : List U8, { start : Nat, count : Nat } -> Result Str [BadUtf8 Utf8ByteProblem Nat, OutOfBounds]*
fromUtf8Range = \bytes, config ->
if config.start + config.count <= List.len bytes then
result = fromUtf8RangeLowlevel bytes config
if result.cIsOk then
Ok result.bString
else
Err (BadUtf8 result.dProblemCode result.aByteIndex)
else
Err OutOfBounds
FromUtf8Result : {
aByteIndex: Nat,
bString: Str,
cIsOk: Bool,
dProblemCode: Utf8ByteProblem,
}
fromUtf8RangeLowlevel : List U8, { start : Nat, count : Nat } -> FromUtf8Result
startsWith : Str, Str -> Bool
endsWith : Str, Str -> Bool
@ -214,19 +243,33 @@ trimLeft : Str -> Str
trimRight : Str -> Str
toDec : Str -> Result Dec [InvalidNumStr]*
toDec = \string -> strToNumHelp string
toF64 : Str -> Result F64 [InvalidNumStr]*
toF64 = \string -> strToNumHelp string
toF32 : Str -> Result F32 [InvalidNumStr]*
toF32 = \string -> strToNumHelp string
toNat : Str -> Result Nat [InvalidNumStr]*
toNat = \string -> strToNumHelp string
toU128 : Str -> Result U128 [InvalidNumStr]*
toU128 = \string -> strToNumHelp string
toI128 : Str -> Result I128 [InvalidNumStr]*
toI128 = \string -> strToNumHelp string
toU64 : Str -> Result U64 [InvalidNumStr]*
toU64 = \string -> strToNumHelp string
toI64 : Str -> Result I64 [InvalidNumStr]*
toI64 = \string -> strToNumHelp string
toU32 : Str -> Result U32 [InvalidNumStr]*
toU32 = \string -> strToNumHelp string
toI32 : Str -> Result I32 [InvalidNumStr]*
toI32 = \string -> strToNumHelp string
toU16 : Str -> Result U16 [InvalidNumStr]*
toU16 = \string -> strToNumHelp string
toI16 : Str -> Result I16 [InvalidNumStr]*
toI16 = \string -> strToNumHelp string
toU8 : Str -> Result U8 [InvalidNumStr]*
toU8 = \string -> strToNumHelp string
toI8 : Str -> Result I8 [InvalidNumStr]*
toI8 = \string -> strToNumHelp string
## Gets the byte at the given index, without performing a bounds check
getUnsafe : Str, Nat -> U8
@ -393,3 +436,15 @@ walkScalarsUntilHelp = \string, state, step, index, length ->
newState
else
state
strToNum : Str -> { berrorcode: U8, aresult : Num * }
strToNumHelp : Str -> Result (Num a) [InvalidNumStr]*
strToNumHelp = \string ->
result : { berrorcode : U8, aresult : Num a }
result = strToNum string
if result.berrorcode == 0 then
Ok result.aresult
else
Err InvalidNumStr