Add missing methods to the standard library (#1284)

This commit is contained in:
Ara Adkins 2020-11-11 16:42:44 +00:00 committed by GitHub
parent 670cffb380
commit a0f87b3611
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 810 additions and 237 deletions

View File

@ -107,7 +107,7 @@ Any.to_json =
cons = Meta.Constructor m.constructor
fs = m.fields
fnames = cons.fields
json_fs = 0.upto fnames.length . fold Map.empty m-> i->
json_fs = 0.up_to fnames.length . fold Map.empty m-> i->
m.insert (fnames.at i) (fs.at i . to_json)
with_tp = json_fs . insert "type" (String cons.name)
Object with_tp

View File

@ -1,5 +1,4 @@
from Builtins import all
from Builtins export Nil, Cons
## PRIVATE
@ -18,8 +17,10 @@ map_helper list cons f = case list of
## The basic cons-list type.
A cons-list allows to store an arbitrary number of elements.
Prepending to the list can be achieved by using the `Cons` constructor,
while an empty list is represented by `Nil`.
> Example
A list containing the elements `1`, `2`, and `3`, in this order is:
Cons 1 (Cons 2 (Cons 3 Nil))
@ -27,6 +28,107 @@ type List
Nil
Cons
## Computes the number of elements in the list.
length : Number
length = this.fold 0 (acc -> _ -> acc + 1)
## Combines all the elements of the list, by iteratively applying the
passed function with next elements of the list.
In general, the result of
(Cons l0 <| Cons l1 <| ... <| Cons ln) . fold init f
is the same as
f (...(f (f init l0) l1)...) ln
> Example
In the following example, we'll compute the sum of all elements of a
list:
(Cons 0 <| Cons 1 <| Cons 2 <| Nil) . fold 0 (+)
fold : Any -> (Any -> Any -> Any) -> Any
fold init f =
go acc list = case list of
Nil -> acc
Cons h t -> @Tail_Call go (f acc h) t
res = go init this
res
## Checks whether any element of the list matches the given predicate.
A predicate is a function that takes a list element and returns
a Boolean value.
> Example
In the following example, we'll check if any element of the list is
larger than `5`:
(Cons 0 <| Cons 1 <| Cons 2 <| Nil) . exists (> 5)
exists : (Any -> Boolean) -> Boolean
exists predicate =
go list = case list of
Nil -> False
Cons h t -> if predicate h then True else
@Tail_Call go t
res = go this
res
## Checks whether any element of the list matches the given predicate.
A predicate is a function that takes a list element and returns
a Boolean value.
> Example
In the following example, we'll check if any element of the list is
larger than `5`:
(Cons 0 <| Cons 1 <| Cons 2 <| Nil) . any (> 5)
any : (Any -> Boolean) -> Boolean
any predicate = this.exists predicate
## Checks whether a predicate holds for all elements in this list.
> Example
Check if all elements in the list are less than zero.
(Cons 1 (Cons 2 Nil)).all (< 0)
all : (Any -> Boolean) -> Boolean
all predicate = this.fold True (l -> r -> l && predicate r)
## Checks whether this list contains a given value as an element.
> Example
Checking if the list contains the number 72.
(Cons 1 (Cons 72 Nil)).contains 72
contains : Any -> Boolean
contains elem = this.exists ix-> ix == elem
## Checks if this list is empty.
> Example
Checking for emptiness.
Nil.is_empty == true
Cons 1 Nil . is_empty == false
is_empty : Boolean
is_empty = this.length == 0
## Checks if the list is not empty.
> Example
Checking for emptiness.
Nil.not_empty == false
Cons 1 Nil . not_empty == true
not_empty : Boolean
not_empty = not this.is_empty
## Selects all elements of this list which satisfy a predicate.
> Example
Selecting all elements that are greater than 3.
(Cons 1 Nil).filter (> 3)
filter : (Any -> Boolean) -> List
filter predicate =
case this of
Cons a b ->
rest = b.filter predicate
if predicate a then Cons a rest else rest
Nil -> Nil
## Applies a function to each element of the list, returning the list of
results.
@ -59,52 +161,94 @@ type List
Cons h t ->
f h
@Tail_Call go t
res = go this
res
## Combines all the elements of the list, by iteratively applying the
passed function with next elements of the list.
In general, the result of
(Cons l0 <| Cons l1 <| ... <| Cons ln) . fold init f
is the same as
f (...(f (f init l0) l1)...) ln
> Example
In the following example, we'll compute the sum of all elements of a
list:
(Cons 0 <| Cons 1 <| Cons 2 <| Nil) . fold 0 (+)
fold : Any -> (Any -> Any -> Any) -> Any
fold init f =
go acc list = case list of
Nil -> acc
Cons h t -> @Tail_Call go (f acc h) t
res = go init this
res
go this
Nothing
## Reverses the list, returning a list with the same elements, but in the
opposite order.
> Example
Reversing a small list.
(Cons 1 (Cons 2 Nil)).reverse == (Cons 2 (Cons 1 Nil))
reverse : List
reverse = this.fold Nil (l -> el -> Cons el l)
## Computes the number of elements in the list.
length : Number
length = this.fold 0 (acc -> _ -> acc + 1)
## Checks whether any element of the list matches the given predicate.
A predicate is a function that takes a list element and returns
a Boolean value.
## Creates a new list with the first `count` elements on the left of `this`
removed.
> Example
In the following example, we'll check if any element of the list is
larger than `1`:
(Cons 0 <| Cons 1 <| Cons 2 <| Nil) . any (> 5)
any : (Any -> Boolean) -> Boolean
any predicate =
go list = case list of
Nil -> False
Cons h t -> if predicate h then True else
@Tail_Call go t
res = go this
res
Removing the first element from a list.
(Cons 1 (Cons 2 (Nil))).drop 1
drop : Integer -> List
drop count = if count <= 0 then this else case this of
Cons _ b -> b.drop count-1
Nil -> Nil
## Creates a new list consisting of the first `count` elements on the left
of this.
> Example
Obtaining the first 2 elements of a list.
(Cons 1 (Cons 2 (Cons 3 Nil))).take 2
take : Integer -> List
take count = if count <= 0 then Nil else case this of
Cons a b -> Cons a (b.take count-1)
Nil -> Nil
## Get the first element from the list.
> Example
This returns 1.
(Cons 1 (Cons 2 Nil)).head
head : Any | Nothing
head = case this of
Cons a _ -> a
Nil -> Nothing
## Get all elements from the list except the first.
> Example
This returns (Cons 2 Nil).
(Cons 1 (Cons 2 Nil)).tail
tail : List | Nothing
tail = case this of
Cons _ b -> b
Nil -> Nothing
## Get all elements from the list except the last.
> Example
Removing the last element of the list to give (Cons 1 Nil).
(Cons 1 (Cons 2 Nil)).init
init : List | Nothing
init =
init' x y = case y of
Nil -> Nil
Cons a b -> Cons x (init' a b)
case this of
Cons a b -> init' a b
Nil -> Nothing
## Get the last element of the list.
> Example
Getting the final element, in this case 2.
(Cons 1 (Cons 2 Nil)).last
last : Any | Nothing
last = this.fold Nothing (_ -> r -> r)
## Get the first element from the list.
> Example
This returns 1.
(Cons 1 (Cons 2 Nil)).first
first : Any | Nothing
first = this.head
## Get all elements from the list except the first.
> Example
This returns (Cons 2 Nil).
(Cons 1 (Cons 2 Nil)).rest
rest : List | Nothing
rest = this.tail

View File

@ -67,16 +67,15 @@ Number.sqrt = Math.sqrt [this.to_decimal]
Number.log : Number -> Decimal
Number.log base = this.ln / base.ln
# TODO this should expose a more-user friendly API in the future.
## Converts a decimal value to a string, using the Java string formatting
syntax.
TODO this should expose a more-user friendly API in the future.
Decimal.format : Text -> Text
Decimal.format fmt = String.format [fmt, this]
## Creates a new right-exclusive range of integers from `this` to `n`.
Integer.upto : Integer -> Range
Integer.upto n = Range this n
Integer.up_to : Integer -> Range
Integer.up_to n = Range this n
## Checks equality of numbers, using an `epsilon` value.

View File

@ -0,0 +1,5 @@
from Base import all
## A pair of elements.
type Pair
type Pair first second

View File

@ -0,0 +1,109 @@
from Base import all
## Represents a right-exclusive range of integer values.
type Range
type Range start end
## Get the number of elements in the range.
> Example
The following range has 100 elements.
0.up_to 100
length : Number
length = this.end - this.start
## Checks if this range is empty.
> Example
0.up_to 0 . is_empty == True
0.up_to 100 . is_empty == False
is_empty : Boolean
is_empty = this.end <= this.start
## Checks if this range is not empty.
> Example
0.up_to 0 . not_empty == False
0.up_to 100 . not_empty == True
not_empty : Boolean
not_empty = not this.is_empty
## Applies a function for each element in the range.
> Example
To print all the numbers from 1 to 100 use:
1.up_to 101 . each IO.println
each : (Number -> Any) -> Nothing
each function =
it start end = if start == end then Nothing else
function start
@Tail_Call it start+1 end
it this.start this.end
Nothing
## Combines all the elements of the range, by iteratively applying the
passed function with next elements of the range.
In general, the result of
Range start end . fold init f
is the same as
f (...(f (f init start) start+1)...) end-1
> Example
In the following example, we'll compute the sum of all elements of a
range:
Range 0 100 . fold 0 (+)
fold : Any -> (Number -> Any) -> Any
fold initial function =
it acc start end = if start == end then acc else
new_acc = function acc start
@Tail_Call it new_acc start+1 end
res = it initial this.start this.end
res
## Checks whether `predicate` is satisfied for all numbers in this range.
A predicate is a function that takes an element in the range and returns
a boolean.
> Example
Checking that all numbers in the range are greater than 5.
10.up_to 100 . all (> 5)
all : (Number -> Boolean) -> Boolean
all predicate =
it start end = if start==end then True else
r = predicate start
if r then (@Tail_Call it start+1 end) else False
res = it this.start this.end
res
## Checks whether `predicate` is satisfied for any number in this range.
A predicate is a function that takes an element in the range and returns
a boolean.
> Example
Checking that at least one number in the range is greater than 10.
1.up_to 100 . exists (> 10)
exists : (Number -> Boolean) -> Boolean
exists predicate = this.fold False (l -> r -> l || predicate r)
## Checks whether `predicate` is satisfied for any number in this range.
A predicate is a function that takes an element in the range and returns
a boolean.
> Example
Checking that at least one number in the range is greater than 10.
1.up_to 100 . any (> 10)
any : (Number -> Boolean) -> Boolean
any predicate = this.exists predicate
## Converts the range to a vector containing the numbers in the range.
> Example
Getting a vector of the numbers 1 to 5.
1.up_to 6 . to_vector == [1, 2, 3, 4, 5]
to_vector : Vector
to_vector = Vector.new (this.end - 1) (i -> i + this.start)

View File

@ -6,6 +6,16 @@ from Builtins export Text
polyglot java import com.ibm.icu.text.BreakIterator
polyglot java import org.enso.base.Text_Utils
## Computes the number of characters in the text.
A character is defined as an Extended Grapheme Cluster, see
[Unicode Standard Annex #29](https://unicode.org/reports/tr29/).
This is the smallest unit that still has semantic meaning in most
text-processing applications.
Text.length : Integer
Text.length = this.characters.length
## Applies `function` to each character in `this`.
A character is defined as an Extended Grapheme Cluster, see
@ -47,11 +57,11 @@ Text.characters =
> Example
In the following example, we'll split the text into a vector of
comma-separated items:
"ham,eggs,cheese,tomatoes".split_at ","
"ham,eggs,cheese,tomatoes".split ","
The code above returns:
["ham", "eggs", "cheese", "tomatoes"]
Text.split_at : Text -> Vector
Text.split_at separator =
Text.split : Text -> Vector
Text.split (separator = " ") =
Vector.from_polyglot_array (Text_Utils.split_at [this, separator])
## Checks whether `this` is equal to `that`.
@ -148,4 +158,4 @@ Text.to_json = Json.String this
concatenated copies of `this`.
Text.repeat : Integer -> Text
Text.repeat count =
0.upto count . fold "" acc-> _-> acc + this
0.up_to count . fold "" acc-> _-> acc + this

View File

@ -17,6 +17,38 @@ from Base import all
type Vector
type Vector to_array
## Creates a new vector of the given length, initializing elements using
the provided constructor function.
The constructor function is called with the consecutive indices
(0-based) of the vector elements.
> Example
To create a vector containing the numbers 1 through 50:
Vector.new 50 (ix -> ix + 1)
> Example
To create a copy of the given vector (`my_vec`):
Vector.new my_vec.length (ix -> my_vec.at ix)
new : Number -> (Number -> Any) -> Vector
new length constructor =
arr = Array.new length
0.up_to length . each ix-> arr.set_at ix (constructor ix)
Vector arr
## Creates a new vector of the given length, filling the elements with
the provided constant.
> Example
A vector containing 50 elements, each being the number `42`, can be
created by:
Vector.fill length=50 item=42
fill : Number -> Any -> Vector
fill length item =
arr = Array.new length
0.up_to length . each ix-> arr.set_at ix item
Vector arr
## Gets an element from the vector at a specified index (0-based).
> Example
@ -56,6 +88,10 @@ type Vector
from_polyglot_array arr = Vector.new arr.length arr.at
## Returns the number of elements stored in this vector.
> Example
Checking the length of a vector.
[1, 2, 3, 4].length == 4
length : Number
length = this.to_array.length
@ -75,56 +111,79 @@ type Vector
fold initial function =
arr = this.to_array
f = acc -> ix -> function acc (arr.at ix)
0.upto this.length . fold initial f
0.up_to this.length . fold initial f
## Checks whether a predicate holds for at least one element of this vector.
exists : (Any -> Any) -> Boolean
exists p =
check found ix = if found then found else p ix
A predicate is a function that takes an element from the vector and
returns a boolean value.
> Example
Checking if any element of the list is larger than 3.
[1,2,3,4,5].exists (> 3)
exists : (Any -> Boolean) -> Boolean
exists predicate =
check found ix = if found then found else predicate ix
this.fold False check
## Checks whether a predicate holds for at least one element of this vector.
A predicate is a function that takes an element from the vector and
returns a boolean value.
> Example
Checking if any element of the list is larger than 3.
[1,2,3,4,5].any (> 3)
any : (Any -> Boolean) -> Boolean
any predicate = this.exists predicate
## Checks whether a predicate holds for all elements in this vector.
> Example
Check if all elements in the vector are less than zero.
[-1, 1, 5, 8].all (< 0)
all : (Any -> Boolean) -> Boolean
all predicate = this.fold True (l -> r -> l && predicate r)
## Checks whether this vector contains a given value as an element.
> Example
Checking if the vector contains the number 72.
[1, 383, 72, 301].contains 72
contains : Any -> Boolean
contains elem = this.exists ix-> ix == elem
## Checks if this vector is empty.
> Example
Checking for emptiness.
[].is_empty == True
[1].is_empty == False
is_empty : Boolean
is_empty = this.length == 0
## Checks if this vector is not empty.
> Example
Checking for non-emptiness.
[].not_empty == False
[1].not_empty == True
not_empty : Boolean
not_empty = not this.is_empty
## Selects all elements of this vector which satisfy a predicate.
A predicate is a function that takes an element from the vector and
returns a boolean value.
> Example
Selecting all elements that are greater than 3.
[1, 2, 3, 4, 5].filter (> 3)
filter : (Any -> Boolean) -> Vector
filter p =
check acc ix = if p ix then acc + [ix] else acc
filter predicate =
check acc ix = if predicate ix then acc + [ix] else acc
this.fold [] check
## Creates a new vector of the given length, initializing elements using
the provided constructor function.
The constructor function is called with the consecutive indices
(0-based) of the vector elements.
> Example
To create a vector containing the numbers 1 through 50:
Vector.new 50 (ix -> ix + 1)
> Example
To create a copy of the given vector (`my_vec`):
Vector.new my_vec.length (ix -> my_vec.at ix)
new : Number -> (Number -> Any) -> Vector
new length constructor =
arr = Array.new length
0.upto length . each ix-> arr.set_at ix (constructor ix)
Vector arr
## Creates a new vector of the given length, filling the elements with
the provided constant.
> Example
A vector containing 50 elements, each being the number `42`, can be
created by:
Vector.fill length=50 item=42
fill : Number -> Any -> Vector
fill length item =
arr = Array.new length
0.upto length . each ix-> arr.set_at ix item
Vector arr
## Applies a function to each element of the vector, returning the vector of
results.
@ -137,37 +196,68 @@ type Vector
map function =
arr = this.to_array
new_arr = Array.new arr.length
0.upto arr.length . each ix-> new_arr.set_at ix (function (arr.at ix))
0.up_to arr.length . each ix-> new_arr.set_at ix (function (arr.at ix))
Vector new_arr
## Applies a function to each element of the vector.
Unlike `map`, this method does not return the individual results,
therefore it is only useful for side-effecting computations.
> Example
In the following example, we're printing each element of the vector
to the standard output:
[1, 2, 3, 4, 5] . each IO.println
each : (Any -> Any) -> Nothing
each f =
this.map f
Nothing
## Reverses the vector, returning a vector with the same elements, but in
the opposite order.
reverse : Vector
reverse = Vector.new this.length (i -> this.at (this.length - (1 + i)))
## Generates a human-readable text representation of the vector.
> Example
Converting a vector of numbers to text.
[1, 2, 3].to_text == "[1, 2, 3]"
to_text : Text
to_text =
arr = this.to_array
if arr.length == 0 then "[]" else
if arr.length == 1 then "[" + (arr.at 0 . to_text) + "]" else
folder = str -> ix -> str + ", " + (arr.at ix).to_text
tail_elems = 1.upto arr.length . fold "" folder
tail_elems = 1.up_to arr.length . fold "" folder
"[" + (arr.at 0 . to_text) + tail_elems + "]"
## Checks whether this vector is equal to `that`. Two vectors are considered
equal, when they have the same length and their items are pairwise equal.
> Example
Comparing two vectors for equality (this case is false).
[1, 2, 3] == [2, 3, 4
== : Vector -> Boolean
== that =
arr1 = this.to_array
arr2 = that.to_array
eq_at i = arr1.at i == arr2.at i
if arr1.length == arr2.length then 0.upto arr1.length . every eq_at else False
if arr1.length == arr2.length then 0.up_to arr1.length . all eq_at else False
## Concatenates two vectors, resulting in a new vector, containing all the
elements of `this`, followed by all the elements of `that`.
> Example
Concatenating two single-element vectors.
[1] + [2] == [1, 2]
+ : Vector -> Vector
+ that =
this_len = this.length
arr = Array.new (this_len + that.length)
0.upto this_len . each i->
0.up_to this_len . each i->
arr.set_at i (this.at i)
this.length.upto arr.length . each i->
this.length.up_to arr.length . each i->
arr.set_at i (that.at i-this_len)
Vector arr
@ -181,28 +271,44 @@ type Vector
join separator =
if this.length == 0 then "" else
if this.length == 1 then this.at 0 else
this.at 0 + (1.upto this.length . fold "" acc-> i-> acc + separator + this.at i)
this.at 0 + (1.up_to this.length . fold "" acc-> i-> acc + separator + this.at i)
## Creates a new vector with the first `count` elements on the left of
`this` removed.
> Example
The following code returns [2, 3, 4, 5]
[1, 2, 3, 4, 5].drop 1
drop : Integer -> Vector
drop count = if count >= this.length then Vector.new 0 (x -> x) else
Vector.new (this.length - count) (i -> this.at i+count)
## Creates a new vector with the last `count` elements on the right of
`this` removed.
> Example
The following code returns [1, 2, 3]
[1, 2, 3, 4, 5].drop_right 2
drop_right : Integer -> Vector
drop_right count = if count >= this.length then Vector.new 0 (x -> x) else
this.take (this.length - count)
## Creates a new vector, consisting of the first `count` elements on the
left of `this`.
> Example
The following code returns [1, 2]
[1, 2, 3, 4, 5].take 2
take : Integer -> Vector
take count = if count >= this.length then this else
Vector.new count this.at
## Creates a new vector, consisting of the last `count` elements on the
right of `this`.
> Example
The following code returns [3, 4, 5]
[1, 2, 3, 4, 5].take_right 3
take_right : Integer -> Vector
take_right count = if count >= this.length then this else
this.drop (this.length - count)
@ -226,6 +332,71 @@ type Vector
to_json : Json.Array
to_json = Json.Array (this.map to_json)
## Get the first element from the vector.
> Example
The following code returns 1.
[1, 2, 3, 4].head
> Example
Empty vectors return `Nothing`.
[].head == Nothing
head : Any | Nothing
head = if this.length >= 1 then this.at 0 else Nothing
## Get all elements in the vector except the first.
> Example
The following code returns [2, 3, 4].
[1, 2, 3, 4].tail
> Example
Empty vectors return `Nothing`.
[].tail == Nothing
tail : Vector | Nothing
tail = if this.length >= 1 then this.drop 1 else Nothing
## Get the all elements in the vector except the last.
> Example
The following code returns [1, 2, 3].
[1, 2, 3, 4].init
> Example
Empty vectors return `Nothing`.
[].init == Nothing
init : Vector | Nothing
init = if this.length >= 1 then this.drop_right 1 else Nothing
## Get the last element of the vector.
> Example
The following code returns 4.
[1, 2, 3, 4].last
> Example
Empty vectors return `Nothing`.
[].last == Nothing
last : Vector | Nothing
last = if this.length >= 1 then (this.take_right 1).at 0 else Nothing
## Get the first element from the vector.
> Example
The following code returns 1.
[1, 2, 3, 4].head
> Example
Empty vectors return `Nothing`.
[].head == Nothing
first : Vector | Nothing
first = this.head
## Get all elements in the vector except the first.
> Example
The following code returns [2, 3, 4].
[1, 2, 3, 4].tail
> Example
Empty vectors return `Nothing`.
[].tail == Nothing
rest : Vector | Nothing
rest = this.tail
## A builder type for Enso vectors.
@ -268,7 +439,7 @@ type Builder
False ->
old_array = this.to_array
new_array = Array.new old_array.length*2
0.upto this.length . each i->
0.up_to this.length . each i->
new_array.set_at i (old_array.at i)
Nothing
Unsafe.set_atom_field this 0 new_array
@ -280,7 +451,7 @@ type Builder
to_vector =
old_array = this.to_array
new_array = Array.new this.length
0.upto this.length . each i->
0.up_to this.length . each i->
new_array.set_at i (old_array.at i)
Nothing
Vector new_array

View File

@ -1,86 +1,41 @@
import Base.Data.Number.Extensions
import Base.Data.Text.Extensions
import Base.Data.List
import Base.Data.Vector
import Base.System.File
import Base.Meta.Enso_Project
import Base.Meta
import Base.Error.Extensions
import Base.Polyglot.Java
import Base.Data.Map
import Base.Data.Json
import Base.Data.List
import Base.Data.Map
import Base.Data.Number.Extensions
import Base.Data.Pair
import Base.Data.Range
import Base.Data.Text.Extensions
import Base.Data.Vector
import Base.Error.Extensions
import Base.Math
import Base.Meta
import Base.Meta.Enso_Project
import Base.Polyglot.Java
import Base.System.File
from Builtins import Nothing, Number, Integer, Any, True, False, Cons, Boolean
export Base.Meta
from Builtins export all hiding Meta
export Base.Data.Map
export Base.Data.Json
from Base.Data.Number.Extensions export all hiding Math, String
from Base.Data.Text.Extensions export Text
from Base.Meta.Enso_Project export all
from Base.Data.List export Nil, Cons
from Base.Data.Vector export Vector
from Base.Error.Extensions export all
from Base.Polyglot.Java export all
export Base.Data.Map
export Base.Math
export Base.Meta
export Base.System.File
## Represents a right-exclusive range of integer values.
type Range
type Range start end
## Applies a function to each element in the range.
> Example
To print all the numbers from 1 to 100 use:
1.upto 101 . each IO.println
each function =
it start end = if start == end then Nothing else
function start
@Tail_Call it start+1 end
it this.start this.end
Nothing
## Combines all the elements of the range, by iteratively applying the
passed function with next elements of the range.
In general, the result of
Range start end . fold init f
is the same as
f (...(f (f init start) start+1)...) end-1
> Example
In the following example, we'll compute the sum of all elements of a
range:
Range 0 100 . fold 0 (+)
fold initial function =
it acc start end = if start == end then acc else
new_acc = function acc start
@Tail_Call it new_acc start+1 end
res = it initial this.start this.end
res
## Checks whether `predicate` is satisfied for every number in this range.
every predicate =
it start end = if start==end then True else
r = predicate start
if r then (@Tail_Call it start+1 end) else False
res = it this.start this.end
res
type Math
## The mathematical constant pi, equal to the ratio of a circle circumference
to its diameter.
Math.pi : Decimal
Math.pi = 3.141592653589793
## A pair of elements.
type Pair
type Pair first second
from Base.Data.List export Nil, Cons
from Base.Data.Number.Extensions export all hiding Math, String
from Base.Data.Pair export Pair
from Base.Data.Range export Range
from Base.Data.Text.Extensions export Text
from Base.Data.Vector export Vector
from Base.Error.Extensions export all
from Base.Meta.Enso_Project export all
from Base.Polyglot.Java export all
from Builtins export all hiding Meta
## Generic equality of arbitrary values.
Two values are considered to be equal in Enso when they have the same
structure, and each of the values of their fields are recursively equal.
Any.== : Any -> Boolean
Any.== that = if Meta.is_same_object this that then True else
this_meta = Meta.meta this
@ -92,7 +47,7 @@ Any.== that = if Meta.is_same_object this that then True else
if not (Meta.is_same_object c_1 c_2) then False else
f_1 = this_meta.fields
f_2 = that_meta.fields
0.upto f_1.length . every i-> (f_1.at i) == (f_2.at i)
0.up_to f_1.length . all i-> (f_1.at i) == (f_2.at i)
Cons (Meta.Error _) (Meta.Error _) -> this_meta.payload == that_meta.payload
Cons (Meta.Polyglot o_1) (Meta.Polyglot o_2) ->
langs_match = this_meta.language == Meta.Java && that_meta.language == Meta.Java

View File

@ -0,0 +1,19 @@
from Base import all
## The mathematical constant pi, equal to the ratio of a circle circumference
to its diameter.
> Example
Calculating the area of a circle.
circle_area r = 2 * Math.pi * r^2
pi : Decimal
pi = 3.1415926535897932385
## The mathematical constant e, the base of the natural logarithm.
> Example
Calculating the natural logarithm of 3.
3.log Math.e
e : Decimal
e = 2.718281828459045235360

View File

@ -84,7 +84,7 @@ pad txt len =
## PRIVATE
print_table header rows =
content_lengths = Vector.new header.length i->
max_row = 0.upto rows.length . fold 0 a-> j-> max a (rows.at j . at i . characters . length)
max_row = 0.up_to rows.length . fold 0 a-> j-> max a (rows.at j . at i . characters . length)
max max_row (header.at i . characters . length)
header_line = zip header content_lengths here.pad . join ' | '
divider = content_lengths . map (l -> "-".repeat l+2) . join '+'

View File

@ -4,7 +4,7 @@ import Test.Bench
polyglot java import java.util.Random
gen_list len = 0.upto len . fold Nil (l -> i -> Cons i+1 l)
gen_list len = 0.up_to len . fold Nil (l -> i -> Cons i+1 l)
sum_list_meta list =
nil_cons = Meta.meta Nil . constructor
@ -20,7 +20,7 @@ sum_recur n = if n == 0 then 0 else 1 + here.sum_recur n-1
build_map size =
rand = Random.new [].to_array
0.upto size . fold Map.empty (m -> i -> m.insert (rand.nextInt [10000]) i)
0.up_to size . fold Map.empty (m -> i -> m.insert (rand.nextInt [10000]) i)
main =
mil = 1000000

View File

@ -5,13 +5,13 @@ import Test.Bench
polyglot java import java.lang.StringBuilder
build_long n =
res = 1.upto n . fold "" acc-> n-> acc + n.to_text
res = 1.up_to n . fold "" acc-> n-> acc + n.to_text
Prim_Text_Helper.optimize res
res
build_long_bldr n =
bldr = new StringBuilder [].to_array
1.upto n . each n-> bldr.append [n]
1.up_to n . each n-> bldr.append [n]
res = bldr.toString []
res

View File

@ -1,16 +1,48 @@
import Test
from Base import all
spec = describe "List" <|
l = Base.Cons 1 <| Base.Cons 2 <| Base.Cons 3 <| Base.Nil
l = Cons 1 <| Cons 2 <| Cons 3 <| Nil
empty = Nil
it "should have properly defined length" <|
l.length.should_equal 3
it "should have well defined length when empty" <|
Nil.length.should_equal 0
it "should allow folding the list with an arbitrary operation with .fold" <|
sum = l.fold 0 (+)
prod = l.fold 1 (*)
sum.should_equal 6
prod.should_equal 6
it "should allow checking if an element satisfies a predicate with .exists" <|
any_even = l.exists (x -> x % 2 == 0)
any_eq_five = l.exists (== 5)
any_even.should_be_true
any_eq_five.should_be_false
it "should allow checking if an element satisfies a predicate with .any" <|
any_even = l.any (x -> x % 2 == 0)
any_eq_five = l.any (== 5)
any_even.should_be_true
any_eq_five.should_be_false
it "should allow checking if all elements satisfy a predicate with `.all`" <|
all_even = l.all(x -> x % 2 == 0)
all_less_than_four = l.all (< 4)
all_even . should_be_false
all_less_than_four . should_be_true
it "should allow checking if an element is in the list with `.contains`" <|
l.contains 4 . should_be_false
l.contains 3 . should_be_true
empty.contains 10 . should_be_false
it "should allow checking if the list is empty with `.is_empty`" <|
l.is_empty . should_be_false
empty.is_empty . should_be_true
it "should allow checking if the list is not empty `.not_empty`" <|
l.not_empty . should_be_true
empty.not_empty . should_be_false
it "should allow filtering of the list using `.filter`" <|
l.filter (> 2) . should_equal (Cons 3 Nil)
it "should allow mapping a function over its elements with .map" <|
l.map +1 . head . should_equal 2
it "should allow reversing with .reverse" <|
l.reverse.head.should_equal 3
it "should allow executing an action for each element with .each" <|
sum = State.run Number 0 <|
l.each el->
@ -18,13 +50,30 @@ spec = describe "List" <|
State.put Number s+el
State.get Number
sum.should_equal 6
it "should allow folding the list with an arbitrary operation with .fold" <|
sum = l.fold 0 (+)
prod = l.fold 1 (*)
sum.should_equal 6
prod.should_equal 6
it "should allow checking if an element satisfies a predicate with .any" <|
any_even = l.any (x -> x % 2 == 0)
any_eq_five = l.any (== 5)
any_even.should_be_true
any_eq_five.should_be_false
it "should allow reversing with .reverse" <|
l.reverse.head.should_equal 3
it "should allow dropping elements from the left with `.drop`" <|
l.drop 1 . should_equal (Cons 2 (Cons 3 Nil))
empty.drop 1 . should_equal Nil
it "should allow taking elements from the left with `.take`" <|
l.take 2 . should_equal (Cons 1 (Cons 2 Nil))
empty.take 2 . should_equal Nil
it "should allow getting the head of the list with `.head`" <|
l.head . should_equal 1
empty.head . should_equal Nothing
it "should allow getting the tail of the list with `.tail`" <|
l.tail . should_equal (Cons 2 (Cons 3 Nil))
empty.tail . should_equal Nothing
it "should allow getting the init of the list with `.init`" <|
l.init . should_equal (Cons 1 (Cons 2 Nil))
empty.init . should_equal Nothing
it "should allow getting the last element of the list with `.last`" <|
l.last . should_equal 3
empty.last . should_equal Nothing
it "should allow getting the head of the list with `.first`" <|
l.first . should_equal 1
empty.first . should_equal Nothing
it "should allow getting the tail of the list with `.rest`" <|
l.rest . should_equal (Cons 2 (Cons 3 Nil))
empty.rest . should_equal Nothing

View File

@ -12,20 +12,20 @@ spec =
hundred_factorial = 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
describe "Integers" <|
it "should be of unbound size when multiplied" <|
1.upto 101 . fold 1 (*) . should_equal hundred_factorial
1.up_to 101 . fold 1 (*) . should_equal hundred_factorial
it "should be of unbound size when added" <|
(almost_max_long + almost_max_long + almost_max_long).should_equal almost_max_long_times_three
it "should be of unbound size when subtracted" <|
(0 - almost_max_long - almost_max_long - almost_max_long).should_equal almost_max_long_times_three.negate
it "should be of unbound size when dividing" <|
expected = 3372816184472482867110284450043137767873196479305249187406461598235841786750685581361224832688174410089430537516012695688121622150430744676
((1.upto 101 . fold 1 (*)).div 3*almost_max_long).should_equal expected
((1.up_to 101 . fold 1 (*)).div 3*almost_max_long).should_equal expected
it "should be of unbound size when taking remainder" <|
expected = 3191479909175673432
((1.upto 101 . fold 1 (*)) % 3*almost_max_long).should_equal expected
((1.up_to 101 . fold 1 (*)) % 3*almost_max_long).should_equal expected
it "should allow defining extension methods through the Integer type for any number size" <|
876543.is_even.should_be_false
(1.upto 101 . fold 1 (*)).is_even.should_be_true
(1.up_to 101 . fold 1 (*)).is_even.should_be_true
it "should handle the negation edge cases" <|
x = 9223372036854775808
y = -x

View File

@ -0,0 +1,38 @@
from Base import all
import Test
spec = describe "Range" <|
it "should be created with a start and an end" <|
range = 1.up_to 100
range.start . should_equal 1
range.end . should_equal 100
it "should have a length" <|
range = 0.up_to 100
range.length . should_equal 100
it "should allow checking for emptiness" <|
0.up_to 0 . is_empty . should_be_true
0.up_to -100 . is_empty . should_be_true
0.up_to 1 . is_empty . should_be_false
0.up_to 5 . is_empty . should_be_false
it "should allow checking for non emptiness" <|
0.up_to 0 . not_empty . should_be_false
0.up_to -100 . not_empty . should_be_false
0.up_to 1 . not_empty . should_be_true
0.up_to 5 . not_empty . should_be_true
it "should allow iteration" <|
vec_mut = Vector.new_builder
1.up_to 6 . each (i -> vec_mut.append i)
vec_mut.to_vector . should_equal [1, 2, 3, 4, 5]
it "should be able to be folded" <|
1.up_to 6 . fold 0 (+) . should_equal 15
it "should check all" <|
1.up_to 10 . all (> 0) . should_be_true
1.up_to 10 . all (< 0) . should_be_false
it "should check exists" <|
1.up_to 10 . exists (> 5) . should_be_true
1.up_to 10 . exists (> 10) . should_be_false
it "should check any" <|
1.up_to 10 . any (> 5) . should_be_true
1.up_to 10 . any (> 10) . should_be_false
it "should allow conversion to vector" <|
1.up_to 6 . to_vector . should_equal [1, 2, 3, 4, 5]

View File

@ -14,6 +14,9 @@ spec = describe "Text" <|
facepalm_codes = [129318, 127996, 8205, 9794, 65039]
accent_1 = '\u00E9'
accent_2 = '\u0065\u{301}'
it "should allow naive length computation over grapheme clusters" <|
kshi.length . should_equal 1
facepalm.length . should_equal 1
it "should compare strings using utf normalization" <|
"abc"=="def" . should_be_false
accent_1 . should_equal accent_2
@ -21,7 +24,7 @@ spec = describe "Text" <|
str = kshi + facepalm + accent_1 + accent_2
str.characters . should_equal [kshi, facepalm, accent_1, accent_2]
it "should split the text on arbitrary sequence" <|
"foo, bar, baz" . split_at ", " . should_equal ["foo", "bar", "baz"]
"foo, bar, baz" . split ", " . should_equal ["foo", "bar", "baz"]
it "should dump utf-8 bytes to a vector" <|
kshi.utf_8.should_equal kshi_utf_8
it "should convert an array of bytes to text" <|

View File

@ -1,24 +1,63 @@
from Base import all
import Test
spec = describe "Vectors" <|
it "should allow vector creation with a programmatic constructor" <|
Vector.new 100 (ix -> ix + 1) . fold 0 (+) . should_equal 5050
it "should allow accessing elements" <|
[1,2,3].at 2 . should_equal 3
it "should have a well-defined length" <|
[1,2,3].length . should_equal 3
it "should allow folding an operator over its elements" <|
[1,2,3].fold 0 (+) . should_equal 6
it "should allow vector creation with a programmatic constructor" <|
Vector.new 100 (ix -> ix + 1) . fold 0 (+) . should_equal 5050
it "should have a well-defined text conversion" <|
[].to_text.should_equal "[]"
[1,2,3].to_text.should_equal "[1, 2, 3]"
[Nothing].to_text.should_equal "[Nothing]"
it "should check exists" <|
vec = [1, 2, 3, 4, 5]
vec.exists (ix -> ix > 3) . should_be_true
vec.exists (ix -> ix < 0) . should_be_false
it "should check any" <|
vec = [1, 2, 3, 4, 5]
vec.any (ix -> ix > 3) . should_be_true
vec.any (ix -> ix < 0) . should_be_false
it "should check all" <|
vec = [1, 2, 3, 4, 5]
vec.all (ix -> ix > 0) . should_be_true
vec.all (ix -> ix < 5) . should_be_false
it "should check contains" <|
vec = [1, 2, 3, 4, 5]
vec.contains 1 . should_be_true
vec.contains 0 . should_be_false
it "should check for emptiness" <|
non_empty = [1]
empty = []
non_empty.is_empty . should_be_false
empty.is_empty . should_be_true
it "should check for non-emptiness" <|
non_empty = [1]
empty = []
non_empty.not_empty . should_be_true
empty.not_empty . should_be_false
it "should filter elements" <|
vec = [1, 2, 3, 4, 5]
vec.filter (ix -> ix > 3) . should_equal [4, 5]
vec.filter (ix -> ix == 1) . should_equal [1]
vec.filter (ix -> ix < 0) . should_equal []
it "should allow mapping an operation, returning a new vector" <|
vec = [1, 2, 3, 4]
mapped = vec.map x-> x * x
vec.to_text.should_equal "[1, 2, 3, 4]"
mapped.to_text.should_equal "[1, 4, 9, 16]"
it "should allow applying a function to each element" <|
vec = [1, 2, 3, 4]
vec_mut = Vector.new_builder
vec.each vec_mut.append
vec_mut.to_vector . should_equal vec
it "should allow reversing" <|
[1, 2, 3].reverse . should_equal [3, 2, 1]
it "should have a well-defined text conversion" <|
[].to_text.should_equal "[]"
[1,2,3].to_text.should_equal "[1, 2, 3]"
[Nothing].to_text.should_equal "[Nothing]"
it "should define equality" <|
[1,2,3]==[1,2] . should_be_false
[1,2,3]==[1,2,3] . should_be_true
@ -34,16 +73,46 @@ spec = describe "Vectors" <|
vec.drop_right 2 . should_equal first_four
vec.take 4 . should_equal first_four
vec.take_right 4 . should_equal last_four
it "should check exists" <|
vec = [1, 2, 3, 4, 5]
vec.exists (ix -> ix > 3) . should_be_true
vec.exists (ix -> ix < 0) . should_be_false
it "should check contains" <|
vec = [1, 2, 3, 4, 5]
vec.contains 1 . should_be_true
vec.contains 0 . should_be_false
it "should filter elements" <|
vec = [1, 2, 3, 4, 5]
vec.filter (ix -> ix > 3) . should_equal [4, 5]
vec.filter (ix -> ix == 1) . should_equal [1]
vec.filter (ix -> ix < 0) . should_equal []
it "should allow getting the head element" <|
non_empty_vec = [1, 2, 3, 4, 5]
singleton_vec = [1]
empty_vec = []
non_empty_vec.head . should_equal 1
singleton_vec.head . should_equal 1
empty_vec.head . should_equal Nothing
it "should allow getting the tail of the vector" <|
non_empty_vec = [1, 2, 3, 4, 5]
singleton_vec = [1]
empty_vec = []
non_empty_vec.tail . should_equal [2, 3, 4, 5]
singleton_vec.tail . should_equal []
empty_vec.tail . should_equal Nothing
it "should allow getting the init of the vector" <|
non_empty_vec = [1, 2, 3, 4, 5]
singleton_vec = [1]
empty_vec = []
non_empty_vec.init . should_equal [1, 2, 3, 4]
singleton_vec.init . should_equal []
empty_vec.init . should_equal Nothing
it "should allow getting the last element of the vector" <|
non_empty_vec = [1, 2, 3, 4, 5]
singleton_vec = [1]
empty_vec = []
non_empty_vec.last . should_equal 5
singleton_vec.last . should_equal 1
empty_vec.last . should_equal Nothing
it "should allow getting the first element" <|
non_empty_vec = [1, 2, 3, 4, 5]
singleton_vec = [1]
empty_vec = []
non_empty_vec.first . should_equal 1
singleton_vec.first . should_equal 1
empty_vec.first . should_equal Nothing
it "should allow getting the rest of the vector" <|
non_empty_vec = [1, 2, 3, 4, 5]
singleton_vec = [1]
empty_vec = []
non_empty_vec.rest . should_equal [2, 3, 4, 5]
singleton_vec.rest . should_equal []
empty_vec.rest . should_equal Nothing

View File

@ -1,43 +1,45 @@
import Test
import Tests.Semantic.Import_Loop.Spec as Import_Loop_Spec
import Tests.Semantic.Deep_Export.Spec as Deep_Export_Spec
import Tests.Semantic.Java_Interop_Spec
import Tests.Semantic.Error_Spec
import Tests.Semantic.Names_Spec
import Tests.Semantic.Import_Loop.Spec as Import_Loop_Spec
import Tests.Semantic.Java_Interop_Spec
import Tests.Semantic.Meta_Spec
import Tests.Semantic.Names_Spec
import Tests.Data.Json_Spec
import Tests.Data.List_Spec
import Tests.Data.Map_Spec
import Tests.Data.Numbers_Spec
import Tests.Data.Range_Spec
import Tests.Data.Text_Spec
import Tests.Data.Time.Spec as Time_Spec
import Tests.Data.Vector_Spec
import Tests.Network.Http_Spec
import Tests.Network.Uri_Spec
import Tests.Network.Http.Header_Spec
import Tests.Network.Http.Request_Spec
import Tests.Network.Http_Spec
import Tests.Network.Uri_Spec
import Tests.System.File_Spec
import Tests.System.Process_Spec
main = Test.Suite.runMain <|
List_Spec.spec
Numbers_Spec.spec
Import_Loop_Spec.spec
Names_Spec.spec
Error_Spec.spec
Deep_Export_Spec.spec
Process_Spec.spec
Error_Spec.spec
File_Spec.spec
Header_Spec.spec
Http_Spec.spec
Import_Loop_Spec.spec
Java_Interop_Spec.spec
Vector_Spec.spec
Json_Spec.spec
List_Spec.spec
Map_Spec.spec
Meta_Spec.spec
Names_Spec.spec
Numbers_Spec.spec
Process_Spec.spec
Range_Spec.spec
Request_Spec.spec
Text_Spec.spec
Time_Spec.spec
File_Spec.spec
Meta_Spec.spec
Map_Spec.spec
Json_Spec.spec
Uri_Spec.spec
Header_Spec.spec
Request_Spec.spec
Http_Spec.spec
Vector_Spec.spec