From c4c35c92b7e2b53f5e4571af0e89a56eac8e7120 Mon Sep 17 00:00:00 2001 From: James Dunkerley Date: Thu, 12 Jan 2023 13:32:24 +0000 Subject: [PATCH] Align Vector API with design, add some extra functions from AoC (#4026) **Vector** - Adjusted `Vector.sort` to be `Vector.sort order on by`. - Adjusted other sort to use `order` for direction argument. - Added `insert`, `remove`, `index_of` and `last_index_of` to `Vector`. - Added `start` and `if_missing` arguments to `find` on `Vector`, and adjusted default is `Not_Found` error. - Added type checking to `+` on `Vector`. - Altered `first`, `second` and `last` to error with `Index_Out_Of_Bounds` on `Vector`. - Removed `sum`, `exists`, `head`, `init`, `tail`, `rest`, `append`, `prepend` from `Vector`. **Pair** - Added `last`, `any`, `all`, `contains`, `find`, `index_of`, `last_index_of`, `reverse`, `each`, `fold` and `reduce` to `Pair`. - Added `get` to `Pair`. **Range** - Added `first`, `second`, `index_of`, `last_index_of`, `reverse` and `reduce` to `Range`. - Added `at` and `get` to `Range`. - Added `start` and `if_missing` arguments to `find` on `Range`. - Simplified `last` and `length` of `Range`. - Removed `exists` from `Range`. **List** - Added `second`, `find`, `index_of`, `last_index_of`, `reverse` and `reduce` to `Range`. - Added `at` and `get` to `List`. - Removed `exists` from `List`. - Made `all` short-circuit if any fail on `List`. - Altered `is_empty` to not compute the length of `List`. - Altered `first`, `tail`, `head`, `init` and `last` to error with `Index_Out_Of_Bounds` on `List`. **Others** - Added `first`, `second`, `last`, `get` to `Text`. - Added wrapper methods to the Random_Number_Generator so you can get random values more easily. - Adjusted `Aggregate_Column` to operate on the first column by default. - Added `contains_key` to `Map`. - Added ALIAS to `row_count` and `order_by`. --- CHANGELOG.md | 3 + .../lib/Standard/Base/0.0.0-dev/package.yaml | 9 +- .../lib/Standard/Base/0.0.0-dev/src/Data.enso | 2 +- .../0.0.0-dev/src/Data/Index_Sub_Range.enso | 4 +- .../Base/0.0.0-dev/src/Data/Json.enso | 8 +- .../Base/0.0.0-dev/src/Data/List.enso | 275 ++++++++++++++---- .../Standard/Base/0.0.0-dev/src/Data/Map.enso | 22 ++ .../Base/0.0.0-dev/src/Data/Pair.enso | 198 ++++++++++++- .../Base/0.0.0-dev/src/Data/Range.enso | 254 ++++++++++++---- .../0.0.0-dev/src/Data/Text/Extensions.enso | 145 ++++++++- .../Base/0.0.0-dev/src/Data/Vector.enso | 263 +++++++++-------- .../Base/0.0.0-dev/src/Error/Common.enso | 3 + .../Standard/Base/0.0.0-dev/src/Function.enso | 2 +- .../Standard/Base/0.0.0-dev/src/Panic.enso | 2 +- .../Standard/Base/0.0.0-dev/src/Random.enso | 31 ++ .../0.0.0-dev/src/System/File_Format.enso | 4 +- .../Database/0.0.0-dev/src/Data/Column.enso | 4 +- .../Database/0.0.0-dev/src/Data/Table.enso | 16 +- .../src/Internal/Base_Generator.enso | 2 +- .../src/Internal/Postgres/Pgpass.enso | 4 +- .../Internal/Postgres/Postgres_Dialect.enso | 4 +- .../src/Internal/SQLite/SQLite_Dialect.enso | 4 +- .../Google_Api/0.0.0-dev/src/Main.enso | 2 +- .../0.0.0-dev/src/Data_Science/Aggregate.enso | 11 +- .../0.0.0-dev/src/Data/Aggregate_Column.enso | 36 +-- .../Table/0.0.0-dev/src/Data/Column.enso | 34 +-- .../Table/0.0.0-dev/src/Data/Table.enso | 30 +- .../src/Delimited/Delimited_Format.enso | 4 +- .../src/Delimited/Delimited_Reader.enso | 4 +- .../0.0.0-dev/src/Internal/Table_Helpers.enso | 8 +- .../Visualization/0.0.0-dev/src/Helpers.enso | 2 +- .../0.0.0-dev/src/Histogram.enso | 2 +- .../0.0.0-dev/src/Scatter_Plot.enso | 2 +- .../0.0.0-dev/src/Table/Visualization.enso | 83 +++--- .../org/enso/compiler/ParseStdLibTest.java | 3 + test/Benchmarks/src/Vector/Operations.enso | 6 +- test/Benchmarks/src/Vector/Sort.enso | 6 +- .../Select_Columns_Spec.enso | 4 +- .../Table_Tests/src/Database/Common_Spec.enso | 2 +- .../src/Formatting/Parse_Values_Spec.enso | 1 - .../src/In_Memory/Column_Spec.enso | 5 +- .../Table_Tests/src/In_Memory/Table_Spec.enso | 11 +- test/Tests/src/Data/List_Spec.enso | 113 +++++-- test/Tests/src/Data/Map_Spec.enso | 4 + test/Tests/src/Data/Pair_Spec.enso | 118 +++++++- test/Tests/src/Data/Range_Spec.enso | 103 ++++++- test/Tests/src/Data/Text_Spec.enso | 44 ++- test/Tests/src/Data/Time/Date_Spec.enso | 2 +- test/Tests/src/Data/Vector_Spec.enso | 113 ++++--- test/Tests/src/Random_Spec.enso | 31 ++ test/Tests/src/Semantic/Warnings_Spec.enso | 4 +- 51 files changed, 1551 insertions(+), 496 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fcc19ab792e8..54a6c4e94957 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -270,6 +270,8 @@ - [Overhauled the JSON support (now based of JavaScript), `Data.fetch` and other minor tweaks][3987] - [Enable Date, Time and DateTime to be read and written to Excel.][3997] +- [Aligning core APIs for Vector, List and Range. Adding some missing functions + to the types.][4026] - [Implemented `Table.distinct` for Database backends.][4027] [debug-shortcuts]: @@ -424,6 +426,7 @@ [3987]: https://github.com/enso-org/enso/pull/3987 [3997]: https://github.com/enso-org/enso/pull/3997 [4013]: https://github.com/enso-org/enso/pull/4013 +[4026]: https://github.com/enso-org/enso/pull/4026 [4027]: https://github.com/enso-org/enso/pull/4027 #### Enso Compiler diff --git a/distribution/lib/Standard/Base/0.0.0-dev/package.yaml b/distribution/lib/Standard/Base/0.0.0-dev/package.yaml index 77a97376429b..6633907e06f0 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/package.yaml +++ b/distribution/lib/Standard/Base/0.0.0-dev/package.yaml @@ -27,20 +27,21 @@ component-groups: - Standard.Base.Data.Text.Regex.escape - Select: exports: - - Standard.Base.Data.Vector.Vector.tail + - Standard.Base.Data.Vector.Vector.at + - Standard.Base.Data.Vector.Vector.get - Standard.Base.Data.Vector.Vector.filter - Standard.Base.Data.Vector.Vector.find - - Standard.Base.Data.Vector.Vector.at - Standard.Base.Data.Vector.Vector.take + - Standard.Base.Data.Vector.Vector.drop - Standard.Base.Data.Vector.Vector.partition - Standard.Base.Data.Vector.Vector.distinct - Join: exports: - - Standard.Base.Data.Vector.Vector.append - - Standard.Base.Data.Vector.Vector.prepend - Standard.Base.Data.Vector.Vector.zip - Transform: exports: + - Standard.Base.Data.Vector.Vector.insert + - Standard.Base.Data.Vector.Vector.remove - Standard.Base.Data.Vector.Vector.map - Standard.Base.Data.Vector.Vector.sort - Standard.Base.Data.Vector.Vector.distinct diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data.enso index a5fa9a84d05e..f700225e2d1f 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data.enso @@ -153,7 +153,7 @@ fetch uri method=HTTP_Method.Get headers=[] parse=True = if response.code.is_success.not then Error.throw (Request_Error.Error "Status Code" ("Request failed with status code: " + response.code + ". " + response.body.to_text)) else response_headers = response.headers - content_type = response_headers.find h-> "Content-Type".equals_ignore_case h.name + content_type = response_headers.find if_missing=Nothing h-> "Content-Type".equals_ignore_case h.name if (parse == False) || (content_type == Nothing) then response else format = Auto_Detect.get_web_parser content_type.value uri if format == Nothing then response else diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Index_Sub_Range.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Index_Sub_Range.enso index 830750f1d025..1d5e8585d30e 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Index_Sub_Range.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Index_Sub_Range.enso @@ -107,7 +107,7 @@ invert_range_selection : Vector Range -> Integer -> Boolean -> Vector Range invert_range_selection ranges length needs_sorting = sorted = if needs_sorting then sort_and_merge_ranges ranges else ranges ranges_with_sentinels = [0.up_to 0] + sorted + [length.up_to length] - ranges_with_sentinels.zip ranges_with_sentinels.tail prev-> next-> + ranges_with_sentinels.zip (ranges_with_sentinels.drop 1) prev-> next-> prev.end.up_to next.start ## PRIVATE @@ -120,7 +120,7 @@ sort_and_merge_ranges ranges = if sorted.is_empty then [] else current_ref = Ref.new sorted.first builder = Vector.new_builder - sorted.tail.each range-> + sorted.drop 1 . each range-> current = current_ref.get case range.start <= current.end of True -> current_ref.put (current.start.up_to (Math.max current.end range.end)) diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Json.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Json.enso index a19ae67f2dc9..3acf4b694cb6 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Json.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Json.enso @@ -110,10 +110,10 @@ type JS_Object from_pairs : Vector -> JS_Object from_pairs pairs = js_object = pairs.fold new_object current->pair-> - case pair.at 0 of + case pair.first of text : Text -> - set_value current text (pair.at 1).to_js_object - current + js_value = pair.second.to_js_object + set_value current text js_value _ -> Error.throw (Illegal_Argument.Error "JS_Object.from_pairs: key must be a Text value") JS_Object.Value js_object @@ -243,7 +243,6 @@ make_javascript enso_object = value = enso_object.get key js_value = make_javascript value set_value current key js_value - current _ : Vector -> enso_object.map make_javascript _ : Array -> Vector.from_polyglot_array enso_object . map make_javascript _ -> enso_object @@ -265,6 +264,7 @@ foreign js get_value object key = """ foreign js set_value object key value = """ object[key] = value + return object foreign js get_property_names object = """ return Object.getOwnPropertyNames(object) diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/List.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/List.enso index 92b7a62c3f83..0acab4f1dd86 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/List.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/List.enso @@ -4,6 +4,8 @@ import project.Data.Numbers.Integer import project.Data.Numbers.Number import project.Data.Text.Text import project.Data.Vector.Vector +import project.Error.Common.Index_Out_Of_Bounds +import project.Error.Common.Not_Found import project.Error.Error import project.Function.Function import project.Nothing.Nothing @@ -38,6 +40,10 @@ type List ## Computes the number of elements in the list. + ! Computational Complexity + + Note that this is a linear operation requiring O(n) time. + > Example Get the length of a two item list. @@ -47,6 +53,54 @@ type List length : Number length self = self.fold 0 (acc -> _ -> acc + 1) + ## Gets an element from the list at a specified index (0-based). + + ! Computational Complexity + + Note that this is a linear operation requiring O(n) time. + + Arguments: + - index: The location in the List to get the element from. The index is + also allowed be negative, then the elements are indexed from the back + of the final item, i.e. -1 will correspond to the last element. + + > Example + Get the second item by index. + + import Standard.Examples + + example_length = Examples.list.length + at : Integer -> Any ! Index_Out_Of_Bounds + at self index = + self.get index (Error.throw (Index_Out_Of_Bounds.Error index self.length)) + + ## Gets an element from the list at a specified index (0-based). + If the index is invalid then `if_missing` is returned. + + ! Computational Complexity + + Note that this is a linear operation requiring O(n) time. + + Arguments: + - index: The location in the List to get the element from. The index is + also allowed be negative, then the elements are indexed from the back + of the final item, i.e. -1 will correspond to the last element. + - if_missing: The value to return if the index is out of bounds. + get : Integer -> Any -> Any + get self index ~if_missing=Nothing = case index >= 0 of + True -> + loop current index = case current of + Nil -> if_missing + Cons x xs -> if index == 0 then x else @Tail_Call loop xs (index - 1) + loop self index + False -> + loop current count lagged = case current of + Nil -> if count == 0 then lagged.x else if_missing + Cons _ xs -> + new_lagged = if count > 0 then lagged else lagged.xs + @Tail_Call loop xs (0.max count-1) new_lagged + loop self -index self + ## Combines all the elements of the list, by iteratively applying the passed function with next elements of the list. @@ -63,7 +117,7 @@ type List In the following example, we'll compute the sum of all elements of a list. - import Standard.Eamples + import Standard.Examples example_fold = Examples.list.fold 0 (+) fold : Any -> (Any -> Any -> Any) -> Any @@ -74,27 +128,23 @@ type List res = go init self res - ## Checks whether any element of the list matches the given predicate. + ## Combines all the elements of a non-empty list using a binary operation. + If the list is empty, it returns `if_empty`. Arguments: - - predicate: A function that takes a list element and returns a boolean - value that says whether that value satisfies the conditions of the - function. + - function: A binary operation that takes two items and combines them. + - if_empty: Value returned if the list is empty. > Example - Check if any element of the list is larger than 5. + Compute the sum of all the elements in a list. import Standard.Examples - example_exists = Examples.list.exists (> 5) - exists : (Any -> Boolean) -> Boolean - exists self predicate = - go list = case list of - Nil -> False - Cons h t -> if predicate h then True else - @Tail_Call go t - res = go self - res + example_fold = Examples.list.reduce (+) + reduce : (Any -> Any -> Any) -> Any -> Any + reduce self function ~if_empty=(Error.throw Empty_Error) = case self of + Nil -> if_empty + Cons x xs -> xs.fold x function ## Checks whether any element of the list matches the given predicate. @@ -113,7 +163,13 @@ type List example_any = Examples.list.any (> 5) any : (Any -> Boolean) -> Boolean - any self predicate = self.exists predicate + any self predicate = + go list = case list of + Nil -> False + Cons h t -> if predicate h then True else + @Tail_Call go t + res = go self + res ## Checks whether a predicate holds for all elements in this list. @@ -129,7 +185,7 @@ type List example_all = Examples.list.all (> 0) all : (Any -> Boolean) -> Boolean - all self predicate = self.fold True (l -> r -> l && predicate r) + all self predicate = self . any (predicate >> .not) . not ## Checks whether this list contains a given value as an element. @@ -143,7 +199,7 @@ type List example_contains = Examples.list.contains 3 contains : Any -> Boolean - contains self elem = self.exists ix-> ix == elem + contains self elem = self.any ix-> ix == elem ## Checks if this list is empty. @@ -154,7 +210,9 @@ type List example_empty = Examples.list.is_empty is_empty : Boolean - is_empty self = self.length == 0 + is_empty self = case self of + Nil -> True + Cons _ _ -> False ## Checks if the list is not empty. @@ -307,32 +365,6 @@ type List go count-1 b res.fill res.value - ## Get the first element from the list. - - > Example - This returns 1. - - import Standard.Examples - - example_head = Examples.list.x - head : Any ! Empty_Error - head self = case self of - Nil -> Error.throw Empty_Error - Cons a _ -> a - - ## Get all elements from the list except the first. - - > Example - This returns (Cons 2 Nil). - - import Standard.Examples - - example_tail = Examples.list.tail - tail : List ! Empty_Error - tail self = case self of - Nil -> Error.throw Empty_Error - Cons _ b -> b - ## Get all elements from the list except the last. > Example @@ -341,10 +373,10 @@ type List import Standard.Examples example_init = Examples.list.init - init : List ! Empty_Error + init : List ! Index_Out_Of_Bounds init self = case self of - Nil -> Error.throw Empty_Error + Nil -> Error.throw (Index_Out_Of_Bounds.Error 0 0) Cons _ Nil -> Nil Cons a b -> go l fill = case l of @@ -367,9 +399,9 @@ type List import Standard.Examples example_last = Examples.list.last - last : Any ! Empty_Error + last : Any ! Index_Out_Of_Bounds last self = case self.fold Nothing (_ -> r -> r) of - Nothing -> Error.throw Empty_Error + Nothing -> Error.throw (Index_Out_Of_Bounds.Error -1 0) a -> a ## Get the first element from the list. @@ -380,19 +412,49 @@ type List import Standard.Examples example_first = Examples.list.first - first : Any ! Empty_Error - first self = self.head + first : Any ! Index_Out_Of_Bounds + first self = case self of + Nil -> Error.throw (Index_Out_Of_Bounds.Error 0 0) + Cons a _ -> a + + ## Get the second element from the list. + + > Example + Getting the second element in the list. + + import Standard.Examples + + example_second = Examples.list.second + second : Any ! Index_Out_Of_Bounds + second self = case self of + Nil -> Error.throw (Index_Out_Of_Bounds.Error 1 0) + Cons _ a -> case a of + Nil -> Error.throw (Index_Out_Of_Bounds.Error 1 1) + Cons b _ -> b + + ## Get the first element from the list. + + > Example + This returns 1. + + import Standard.Examples + + example_head = Examples.list.x + head : Any ! Index_Out_Of_Bounds + head self = self.first ## Get all elements from the list except the first. > Example - Getting all elements in the list except the first. + This returns (Cons 2 Nil). import Standard.Examples - example_rest = Examples.list.rest - rest : List ! Empty_Error - rest self = self.tail + example_tail = Examples.list.tail + tail : List ! Index_Out_Of_Bounds + tail self = case self of + Nil -> Error.throw (Index_Out_Of_Bounds.Error 1 0) + Cons _ b -> b ## UNSTABLE Convert this list to a vector with the same elements. @@ -402,6 +464,7 @@ type List builder.append elem builder.to_vector + ## Generates a human-readable text representation of the list. to_text : Text to_text self = go l t e = case l of @@ -409,6 +472,90 @@ type List Cons x xs -> @Tail_Call go xs (t + "(Cons " + x.to_text + " ") (")" + e) go self "" "" + ## Returns the first element of the list that satisfies the predicate or + if no elements of the list satisfy the predicate, returns `if_missing`. + + Arguments: + - predicate: A function that takes a list element and returns a boolean + value that says whether that value satisfies the conditions of the + function. + - start: The index to start searching from. If the index is negative, it + is counted from the end of the vector. + - if_missing: Value returned if no element satisfies the predicate. + + > Example + Finding a first element of the list that is larger than 2. + + import Standard.Examples + + example_first = Examples.list.find (> 2) + find : (Any -> Boolean) -> Integer -> Any -> Any + find self predicate start=0 ~if_missing=(Error.throw Not_Found) = case start.signum of + -1 -> + node_and_index = find_node_from_end self start + node_and_index.first.find predicate 0 if_missing + _ -> + start_node = find_node_from_start self start + loop current = case current of + Nil -> if_missing + Cons x xs -> if predicate x then x else @Tail_Call loop xs + loop start_node + + ## Returns the index of the element in the list. + Returns Nothing if the element is not found. + + Arguments: + - element: The element to search for or a predicate function to test for + each element. + - start: The index to start searching from. If the index is negative, it + is counted from the end of the list. + + > Example + Finding a first element of the vector that is larger than 3. + + [1, 2, 3, 4, 5].find (> 3) + index_of : (Any | (Any -> Boolean)) -> Integer -> Integer | Nothing + index_of self element start=0 = case start.signum of + -1 -> + node_and_index = find_node_from_end self start + found = node_and_index.first.index_of element 0 + if found.is_nothing then Nothing else found+node_and_index.second + _ -> + start_node = find_node_from_start self start + predicate = if element.is_a Function then element else (==element) + loop current idx = case current of + Nil -> Nothing + Cons x xs -> if predicate x then idx else @Tail_Call loop xs idx+1 + loop start_node start + + ## Returns the last index of the element in the list. + Returns Nothing if the element is not found. + + Arguments: + - element: The element to search for or a predicate function to test for + each element. + - start: The index to start searching backwards from. If the index is + negative, it is counted from the end of the list. + + > Example + Finding a first element of the vector that is larger than 3. + + [1, 2, 3, 4, 5].find (> 3) + last_index_of : (Any | (Any -> Boolean)) -> Integer -> Integer | Nothing + last_index_of self element start=-1 = case self of + Nil -> if start == -1 || start == 0 then Nothing else Error.throw (Index_Out_Of_Bounds.Error start 0) + Cons _ _ -> + length = self.length + used_start = if start < 0 then length+start else start + if used_start < 0 || used_start >= length then Error.throw (Index_Out_Of_Bounds.Error start length) else + predicate = if element.is_a Function then element else (==element) + loop current idx last_match = if idx>used_start then last_match else case current of + Nil -> last_match + Cons x xs -> + new_match = if predicate x then idx else last_match + @Tail_Call loop xs idx+1 new_match + loop self 0 Nothing + ## UNSTABLE An error representing that the list is empty. @@ -419,3 +566,21 @@ type Empty_Error to_display_text : Text to_display_text self = "The List is empty." +## PRIVATE + Given a positive index and a list, returns the node. +find_node_from_start list index = + loop current idx = case current of + Nil -> if idx == 0 then current else Error.throw (Index_Out_Of_Bounds.Error index index-idx+1) + Cons _ xs -> if idx == 0 then current else @Tail_Call loop xs (idx - 1) + loop list index + +## PRIVATE + Given a negative index and a list, returns the node that is represented and the index of it. +find_node_from_end list index = + loop current count lagged idx = case current of + Nil -> if count == 0 then [lagged, idx] else Error.throw (Index_Out_Of_Bounds.Error index -index-count) + Cons _ xs -> + new_lagged = if count > 0 then lagged else lagged.xs + new_idx = if count > 0 then idx else idx+1 + @Tail_Call loop xs (0.max count-1) new_lagged new_idx + loop list -index list 0 diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Map.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Map.enso index 4dd06cf9cfd5..cceca084485a 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Map.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Map.enso @@ -229,6 +229,28 @@ type Map result = go self result + ## Checks if a key is in the map. + + Arguments: + - key: The key to look up in the map. + + > Example + Checks the key 2 is in a map. + + import Standard.Base.Data.Map.Map + import Standard.Examples + + example_contains = Examples.map.contains_key 2 + contains_key : Any -> Any + contains_key self key = + go map = case map of + Map.Tip -> False + Map.Bin _ k _ l r -> case Internal.compare_allow_nothing key k of + Ordering.Equal -> True + Ordering.Less -> @Tail_Call go l + Ordering.Greater -> @Tail_Call go r + go self + ## Transforms the map's keys and values to create a new map. Arguments: diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Pair.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Pair.enso index 408933b8c1e8..87da8956dd84 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Pair.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Pair.enso @@ -1,8 +1,12 @@ import project.Any.Any +import project.Data.Boolean.Boolean import project.Data.Numbers.Integer import project.Data.Vector.Vector -import project.Error.Error import project.Error.Common.Index_Out_Of_Bounds +import project.Error.Common.Not_Found +import project.Error.Error +import project.Function.Function +import project.Nothing.Nothing ## A pair of elements. type Pair @@ -23,6 +27,15 @@ type Pair - second: The second element. Value first second + ## Get the last element of the pair. + + > Example + The following code returns 4. + + Pair.new 2 4 . last + last : Any + last self = self.second + ## UNSTABLE Applies the provided function to both elements of the pair. @@ -53,9 +66,190 @@ type Pair of the pair, i.e. -1 will correspond to the last element. at : Integer -> Any at self index = + self.get index (Error.throw (Index_Out_Of_Bounds.Error index 2)) + + ## Gets an element from the pair at a specified index (0-based). + If the index is invalid then `if_missing` is returned. + + Arguments: + - index: The location in the pair to get the element from. The index is + also allowed be negative, then the elements are indexed from the back + of the pair, i.e. -1 will correspond to the last element. + - if_missing: The value to return if the index is out of bounds. + get : Integer -> Any -> Any + get self index ~if_missing=Nothing = case index of 0 -> self.first 1 -> self.second -1 -> self.second -2 -> self.first - _ -> Error.throw (Index_Out_Of_Bounds.Error index self.length) + _ -> if_missing + + ## Checks whether a predicate holds for at least one element of self pair. + + Arguments: + - predicate: A function that takes a list element and returns a boolean + value that says whether that value satisfies the conditions of the + function. + + > Example + Checking if any element of the list is larger than 3. + + Pair.new 1 5 . any (> 3) + any : (Any -> Boolean) -> Boolean + any self predicate = predicate self.first || predicate self.second + + ## Checks whether a predicate holds for all elements in this pair. + + Arguments: + - predicate: A function that takes a list element and returns a boolean + value that says whether that value satisfies the conditions of the + function. + + > Example + Check if all elements in the pair are less than zero. + + Pair.new -1 3 . all (< 0) + all : (Any -> Boolean) -> Boolean + all self predicate = predicate self.first && predicate self.second + + ## Checks whether this pair contains a given value as an element. + + Arguments: + - elem: The item to see if it exists in the pair. + + > Example + Checking if the vector contains the number 72. + + Pair.new 1 42 . contains 72 + contains : Any -> Boolean + contains self elem = self.first == elem || self.second == elem + + ## Returns the first element of the pair that satisfies the predicate or + if no elements satisfy the predicate, returns `if_missing`. + + Arguments: + - predicate: A function that takes a list element and returns a boolean + value that says whether that value satisfies the conditions of the + function. + - start: The index to start searching from. If the index is negative, it + is counted from the end of the pair. + - if_missing: Value returned if no element satisfies the predicate. + + > Example + Finding a first element of the pair that is larger than 3. + + Pair.new 1 6 .find (> 3) + find : (Any -> Boolean) -> Integer -> Any -> Any + find self predicate start=0 ~if_missing=(Error.throw Not_Found) = + check_start_valid start used_start-> + if used_start<1 && predicate self.first then self.first else + if used_start<2 && predicate self.second then self.second else + if_missing + + ## Returns the index of an element in the pair. + Returns Nothing if the element is not found. + + Arguments: + - element: The element to search for or a predicate function to test for + each element. + - start: The index to start searching from. If the index is negative, it + is counted from the end of the pair. + + > Example + Find the index of an element in a pair. + + Pair.new 1 2 . index_of 2 == 1 + Pair.new 2 2 . index_of 2 == 0 + index_of : (Any | (Any -> Boolean)) -> Integer -> Integer | Nothing + index_of self element start=0 = check_start_valid start used_start-> + predicate = case element of + _ : Function -> element + _ -> (==element) + if used_start<1 && predicate self.first then 0 else + if used_start<2 && predicate self.second then 1 else + Nothing + + ## Returns the last index of an element in the pair. + Returns Nothing if the element is not found. + + Arguments: + - element: The element to search for or a predicate function to test for + each element. + - start: The index to start searching backwards from. If the index is + negative, it is counted from the end of the pair. + + > Example + Find the last index of an element in a pair. + + Pair.new 2 2 . last_index_of 2 == 1 + last_index_of : (Any | (Any -> Boolean)) -> Integer -> Integer | Nothing + last_index_of self element start=-1 = check_start_valid start max=2 used_start-> + predicate = case element of + _ : Function -> element + _ -> (==element) + if used_start>0 && predicate self.second then 1 else + if used_start>=0 && predicate self.first then 0 else + Nothing + + ## Combines all the elements of the pair, by iteratively applying the + passed function with next elements of the pair. + + Arguments: + - init: The initial value for the fold. + - function: A function taking two elements and combining them. + + > Example + Compute the sum of all of the elements in a pair. + + Pair.new 10 20 . fold 0 (+) + fold : Any -> (Any -> Any -> Any) -> Any + fold self init function = + function (function init self.first) self.second + + ## Combines all the elements of the pair using a binary operation. + + Arguments: + - function: A binary operation that takes two items and combines them. + + > Example + Compute the sum of all the elements in a Pair. + + Pair.new 10 20 . reduce (+) + reduce : (Any -> Any -> Any) -> Any + reduce self function = + function self.first self.second + + ## Reverses the pair, returning a pair with the same elements, but in + the opposite order. + + > Example + Reverse a two-element vector. + + Pair.new 1 2 . reverse + reverse : Pair + reverse self = Pair.new self.second self.first + + ## Applies a function to each element of the pair. + + Unlike `map`, this method does not return the individual results, + therefore it is only useful for side-effecting computations. + + Arguments: + - function: A function to apply to each element of the pair. + + > Example + Print each element in the vector to standard output. + + Pair.new 1 2 . each IO.println + each : (Any -> Any) -> Nothing + each self f = + f self.first + f self.second + Nothing + +## PRIVATE +check_start_valid start function max=3 = + used_start = if start < 0 then start + 2 else start + if used_start < 0 || used_start >= max then Error.throw (Index_Out_Of_Bounds.Error start max) else + function used_start diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Range.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Range.enso index b7cd95b4d0de..8a92fc688cd7 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Range.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Range.enso @@ -2,7 +2,9 @@ import project.Any.Any import project.Data.Filter_Condition.Filter_Condition import project.Data.Numbers.Integer import project.Data.Numbers.Number +import project.Data.Text.Text import project.Data.Vector.Vector +import project.Error.Common.Index_Out_Of_Bounds import project.Error.Error import project.Error.Illegal_Argument.Illegal_Argument import project.Function.Function @@ -53,18 +55,21 @@ type Range _ -> Error.throw (Illegal_Argument.Error "Range step should be an integer.") + ## Returns the first element that is included within the range or `Nothing` + if the range is empty. + first : Integer ! Index_Out_Of_Bounds + first self = if self.is_empty then Error.throw (Index_Out_Of_Bounds.Error 0 0) else self.start + + ## Returns the second element that is included within the range or `Nothing` + if the range has less than 2 element + second : Integer ! Index_Out_Of_Bounds + second self = if self.length < 2 then Error.throw (Index_Out_Of_Bounds.Error 1 self.length) else self.start + self.step + ## Returns the last element that is included within the range or `Nothing` if the range is empty. - last : Integer | Nothing - last self = if self.is_empty then Nothing else case self.step > 0 of - True -> - diff = self.end - self.start - rem = diff % self.step - if rem == 0 then self.end - self.step else self.end - rem - False -> - diff = self.start - self.end - rem = diff % (-self.step) - if rem == 0 then self.end - self.step else self.end + rem + last : Integer ! Index_Out_Of_Bounds + last self = if self.is_empty then Error.throw (Index_Out_Of_Bounds.Error 0 0) else + self.start + self.step*(self.length - 1) ## Get the number of elements in the range. @@ -73,9 +78,45 @@ type Range 0.up_to 100 . length length : Number - length self = case self.last of - Nothing -> 0 - last -> ((last - self.start) . div self.step) + 1 + length self = if self.is_empty then 0 else + diff = self.end - self.start + steps = diff . div self.step + if self.start + steps*self.step == self.end then steps else steps+1 + + ## Gets an element from the Range at a specified index (0-based). + + Arguments: + - index: The location in the Range to get the element from. The index is + also allowed be negative, then the elements are indexed from the back + of the final item, i.e. -1 will correspond to the last element. + + > Example + Get the second element of a range. + + 0.up_to 10 . get 1 == 1 + + > Example + Get the last element of a range with step. + + 0.up_to 10 . with_step 2 . get -1 == 8 + at : Integer -> Any ! Index_Out_Of_Bounds + at self index = + self.get index (Error.throw (Index_Out_Of_Bounds.Error index self.length)) + + ## Gets an element from the Range at a specified index (0-based). + If the index is invalid then `if_missing` is returned. + + Arguments: + - index: The location in the Range to get the element from. The index is + also allowed be negative, then the elements are indexed from the back + of the Range, i.e. -1 will correspond to the last element. + - if_missing: The value to return if the index is out of bounds. + get : Integer -> Any -> Any + get self index ~if_missing=Nothing = + len = self.length + used_index = if index < 0 then len + index else index + if used_index >= 0 && used_index < len then self.start + used_index * self.step else + if_missing ## Checks if this range is empty. @@ -235,21 +276,7 @@ type Range 10.up_to 100 . all (> 5) all : (Number -> Boolean) -> Boolean - all self predicate = self . exists (predicate >> .not) . not - - ## Checks whether `predicate` is satisfied for any number in this range. - - Arguments: - - predicate: A function that takes a list element and returns a boolean - value that says whether that value satisfies the conditions of the - function. - - > 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 self predicate = self.find predicate . is_nothing . not + all self predicate = self . any (predicate >> .not) . not ## Checks whether `predicate` is satisfied for any number in this range. @@ -263,38 +290,28 @@ type Range 1.up_to 100 . any (> 10) any : (Number -> Boolean) -> Boolean - any self predicate = self.exists predicate + any self predicate = self.find predicate . is_nothing . not ## Gets the first index when `predicate` is satisfied this range. - If no index satisfies the predicate, return Nothing + If no index satisfies the predicate, returns `if_missing`. Arguments: - predicate: A function that takes a list element and returns a boolean value that says whether that value satisfies the conditions of the function. + - start: The index to start searching from. If the index is negative, it + is counted from the end of the range. + - if_missing: Value returned if no element satisfies the predicate. > Example Get the first number in the range divisible by 2, 3 and 5. 1.up_to 100 . find i->(i%2==0 && i%3==0 && i%5==0) - find : (Integer -> Boolean) -> Integer | Nothing - find self predicate = - if self.step == 0 then throw_zero_step_error else - end_condition = if self.step > 0 then (>=) else (<=) - go current = - if end_condition current self.end then Nothing else - if predicate current then current else - @Tail_Call go current+self.step - go self.start - - ## 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 - to_vector : Vector - to_vector self = self.map x->x + find : (Integer -> Boolean) -> Integer -> Any -> Any + find self predicate start=0 ~if_missing=Nothing = + check_start_valid start self used_start-> + result = find_internal self used_start predicate + if result.is_nothing then if_missing else result.first ## Checks if the range contains the specified value. @@ -313,8 +330,145 @@ type Range add this so that we avoid a confusing `Range 0 10 . contains 3.0 == False` and get a type error for decimals instead. - _ -> - Error.throw (Illegal_Argument.Error "`Range.contains` only accepts Integers.") + _ -> Error.throw (Illegal_Argument.Error "`Range.contains` only accepts Integers.") + + ## Returns the index of an element in the range. + Returns Nothing if the element is not found. + + Arguments: + - element: The integer to search for or a predicate function to test for + each element. + - start: The index to start searching from. If the index is negative, it + is counted from the end of the range. + + > Example + Find the index of an element in a range. + + 0.up_to 100 . index_of 20 == 20 + 0.up_to 100 . with_step 5 . index_of 20 == 4 + 0.up_to 100 . with_step 5 . index_of (>10) == 3 + index_of : (Integer | (Any -> Boolean)) -> Integer -> Integer | Nothing + index_of self element start=0 = + check_start_valid start self used_start-> + case element of + _ : Integer -> get_index self used_start self.length-1 element + _ : Function -> + result = find_internal self used_start element + if result.is_nothing then Nothing else result.second + _ -> Error.throw (Illegal_Argument.Error "`Range.index_of` only accepts Integers or a predicate.") + + ## Returns the last index of an element in the range. + Returns Nothing if the element is not found. + + Arguments: + - element: The integer to search for or a predicate function to test for + each element. + - start: The index to start searching backwards from. If the index is + negative, it is counted from the end of the range. + + > Example + Find the last index of an element in a pair. + + Pair.new 2 2 . last_index_of 2 == 1 + last_index_of : (Any | (Any -> Boolean)) -> Integer -> Integer | Nothing + last_index_of self element start=-1 = + if self.is_empty && (start==-1 || start==0) then Nothing else + check_start_valid start self include_end=False used_start-> + case element of + _ : Integer -> get_index self 0 used_start element + _ : Function -> + start_value = self.start + used_start*self.step + go current idx = + if element current then idx else + if current == self.start then Nothing else + @Tail_Call go current-self.step idx-1 + go start_value used_start + _ -> Error.throw (Illegal_Argument.Error "`Range.last_index_of` only accepts Integers or a predicate.") + + ## Reverses the range, returning a range with the same elements, but in + the opposite order. + + > Example + Reverse a step 5 from 0 to 23 + + Range.new 0 23 . with_step 5 . reverse + reverse : Range + reverse self = + if self.step == 0 then throw_zero_step_error else + Range.Between self.last (self.first-self.step) (-self.step) + + ## 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 + to_vector : Vector + to_vector self = self.map x->x + + ## Combines all the elements of a non-empty range using a binary operation. + If the range is empty, returns `if_empty`. + + Arguments: + - function: A binary operation that takes two items and combines them. + - if_empty: Value returned if the range is empty. + + > Example + Compute the sum of all the elements in a range. + + 0.up_to 10 . reduce (+) + reduce : (Any -> Any -> Any) -> Any -> Any + reduce self function ~if_empty=(Error.throw Empty_Error) = + len = self.length + case len of + 0 -> if_empty + 1 -> self.start + _ -> + end_condition = if self.step > 0 then (>=self.end) else (<=self.end) + fold_function current value = + if end_condition value then current else + @Tail_Call fold_function (function current value) (value + self.step) + fold_function self.start self.start+self.step ## PRIVATE throw_zero_step_error = Error.throw (Illegal_State.Error "A range with step = 0 is ill-formed.") + +## PRIVATE + Check inputs are valid for a range +check_start_valid start range function include_end=True = + if range.step == 0 then throw_zero_step_error else + self_len = range.length + used_start = if start < 0 then start + self_len else start + max = if include_end then self_len+1 else self_len + if used_start < 0 || used_start >= max then Error.throw (Index_Out_Of_Bounds.Error start max) else + function used_start + +## PRIVATE + Find value and index for a predicate +find_internal range start predicate = + end_condition = if range.step > 0 then (>=) else (<=) + start_value = range.start + start*range.step + go current idx = + if end_condition current range.end then Nothing else + if predicate current then [current, idx] else + @Tail_Call go current+range.step idx+1 + go start_value start + +## PRIVATE + Work out the index of a value in a range +get_index range min max value = + diff = value - range.start + if diff % range.step != 0 then Nothing else + index = (diff / range.step).floor + if index < min || index > max then Nothing else + index + +## UNSTABLE + + An error representing that the list is empty. +type Empty_Error + ## PRIVATE + + Pretty prints the empty error. + to_display_text : Text + to_display_text self = "The Range is empty." diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Extensions.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Extensions.enso index eca04047b11a..0d063b890408 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Extensions.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Extensions.enso @@ -108,20 +108,87 @@ Text.each self function = "건반(Korean)".at 1 == "반" Text.at : Integer -> Text ! Index_Out_Of_Bounds Text.at self index = + self.get index (Error.throw (Index_Out_Of_Bounds.Error index self.length)) + +## ALIAS Get Character + + Returns a character from the text at the specified index (0-based). + If the index is invalid then `if_missing` is returned. + + Arguments: + - index: The location in the text to get the character from. The + index is also allowed be negative, then the characters are + counted from the end of the text, i.e. -1 will correspond to the + last character. + - if_missing: The value to return if the index is out of bounds. + + ! What is a Character? + A character is defined as an Extended Grapheme Cluster, see Unicode + Standard Annex 29. This is the smallest unit that still has semantic + meaning in most text-processing applications. + + > Example + Get the individual characters in the text "건반(Korean)". + + "건반(Korean)".get 1 == "반" +Text.get : Integer -> Any -> Any +Text.get self index ~if_missing=Nothing = case index < 0 of True -> length = self.length new_index = index + length - if new_index < 0 then Error.throw (Index_Out_Of_Bounds.Error index length) else + if new_index < 0 then if_missing else self.at new_index False -> iterator = BreakIterator.getCharacterInstance iterator.setText self first = iterator.next index next = if first == -1 then -1 else iterator.next - if (next == -1) then (Error.throw (Index_Out_Of_Bounds.Error index self.length)) else + if (next == -1) then if_missing else Text_Utils.substring self first next +## Returns the first character from the text. + + ! What is a Character? + A character is defined as an Extended Grapheme Cluster, see Unicode + Standard Annex 29. This is the smallest unit that still has semantic + meaning in most text-processing applications. + + > Example + Get the first character in the text "건반(Korean)". + + "건반(Korean)".first == "건" +Text.first : Text ! Index_Out_Of_Bounds +Text.first self = self.at 0 + +## Returns the second character from the text. + + ! What is a Character? + A character is defined as an Extended Grapheme Cluster, see Unicode + Standard Annex 29. This is the smallest unit that still has semantic + meaning in most text-processing applications. + + > Example + Get the second character in the text "건반(Korean)". + + "건반(Korean)".second == "반" +Text.second : Text ! Index_Out_Of_Bounds +Text.second self = self.at 1 + +## Returns the last character from the text. + + ! What is a Character? + A character is defined as an Extended Grapheme Cluster, see Unicode + Standard Annex 29. This is the smallest unit that still has semantic + meaning in most text-processing applications. + + > Example + Get the last character in the text "건반(Korean)". + + "건반(Korean)".last == ")" +Text.last : Text ! Index_Out_Of_Bounds +Text.last self = self.at -1 + ## ALIAS Get Characters Returns a vector containing all characters in the given text. @@ -1053,7 +1120,7 @@ Text.trim self where=Location.Both what=_.is_whitespace = if start_index >= end_index then "" else Text_Utils.substring self start_index end_index -## ALIAS index_of, position_of, span_of +## ALIAS position_of, span_of Find the location of the `term` in the input. Returns a Span representing the location at which the term was found, or `Nothing` if the term was not found in the input. @@ -1268,6 +1335,78 @@ Text.locate_all self term="" matcher=Text_Matcher.Case_Sensitive = if term.is_em Nothing -> [] matches -> matches.map m-> m.span 0 . to_grapheme_span +## Find the first index of the `term` in the input. + Returns `Nothing` if the term was not found in the input. + + Using `locate` is preferred as then you can also get the length of the match + which may not necessarily be equal to the length of the searched term - not + only in case of regex matching but also in case insensitive mode. + See the Match Length section of `locate` for an explanation. + + Arguments: + - term: The term to find. + - start: The index to start searching from. If the index is negative, it + is counted from the end of the vector. + - matcher: Specifies how the term is matched against the input: + - If a `Text_Matcher`, the text is compared using case-sensitively rules + specified in the matcher. + - If a `Regex_Matcher`, the `term` is used as a regular expression and + matched using the associated options. + + ! What is a Character? + A character is defined as an Extended Grapheme Cluster, see Unicode + Standard Annex 29. This is the smallest unit that still has semantic + meaning in most text-processing applications. + + > Example + Finding location of a substring. + + "Hello World!".index_of "J" == Nothing + "Hello World!".index_of "o" == 4 +Text.index_of : Text -> Integer -> (Text_Matcher | Regex_Matcher) -> Integer | Nothing +Text.index_of self term="" start=0 matcher=Text_Matcher.Case_Sensitive = + used_start = if start < 0 then start+self.length else start + if used_start < 0 || used_start > self.length then Error.throw (Index_Out_Of_Bounds.Error start self.length+1) else + used = if used_start == 0 then self else self.drop used_start + span = used.locate term Matching_Mode.First matcher + if span.is_nothing then Nothing else span.start+used_start + +## Find the last index of the `term` in the input. + Returns `Nothing` if the term was not found in the input. + + Using `locate` is preferred as then you can also get the length of the match + which may not necessarily be equal to the length of the searched term - not + only in case of regex matching but also in case insensitive mode. + See the Match Length section of `locate` for an explanation. + + Arguments: + - term: The term to find. + - start: The index to start searching backwards from. If the index is + negative, it is counted from the end of the vector. + - matcher: Specifies how the term is matched against the input: + - If a `Text_Matcher`, the text is compared using case-sensitively rules + specified in the matcher. + - If a `Regex_Matcher`, the `term` is used as a regular expression and + matched using the associated options. + + ! What is a Character? + A character is defined as an Extended Grapheme Cluster, see Unicode + Standard Annex 29. This is the smallest unit that still has semantic + meaning in most text-processing applications. + + > Example + Finding location of a substring. + + "Hello World!".last_index_of "J" == Nothing + "Hello World!".last_index_of "o" == 7 +Text.last_index_of : Text -> Integer -> (Text_Matcher | Regex_Matcher) -> Integer | Nothing +Text.last_index_of self term="" start=-1 matcher=Text_Matcher.Case_Sensitive = + used_start = if start < 0 then start+self.length else start + if used_start < 0 || used_start >= self.length then Error.throw (Index_Out_Of_Bounds.Error start self.length) else + used = if used_start == self.length-1 then self else self.take used_start+1 + span = used.locate term Matching_Mode.Last matcher + if span.is_nothing then Nothing else span.start + ## PRIVATE Returns a new Text constructed by slicing the input according to the provided ranges. The ranges are assumed to have step equal to 1 and bounds within the diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso index 652c929b159a..7681223e848f 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso @@ -12,6 +12,8 @@ import project.Data.Range.Extensions import project.Data.Text.Text import project.Error.Common.Index_Out_Of_Bounds import project.Error.Common.No_Such_Method +import project.Error.Common.Not_Found +import project.Error.Common.Type_Error import project.Error.Error import project.Error.Illegal_Argument.Illegal_Argument import project.Error.Incomparable_Values.Incomparable_Values @@ -239,21 +241,21 @@ type Vector a built.to_vector ## Combines all the elements of a non-empty vector using a binary operation. + If the vector is empty, it returns `if_empty`. Arguments: - function: A binary operation that takes two items and combines them. - - If the vector is empty, it throws an `Empty_Error`. + - if_empty: Value returned if the vector is empty. > Example Compute the sum of all the elements in a vector. [0, 1, 2] . reduce (+) - reduce : (Any -> Any -> Any) -> Any ! Empty_Error - reduce self function = + reduce : (Any -> Any -> Any) -> Any -> Any + reduce self function ~if_empty=(Error.throw Empty_Error) = len = self.length case len of - 0 -> Error.throw Empty_Error + 0 -> if_empty 1 -> self.at 0 _ -> fold_function current idx = @@ -261,54 +263,72 @@ type Vector a @Tail_Call fold_function (function current (self.at idx)) (idx + 1) fold_function (self.at 0) 1 - ## Computes the sum of the values in the vector. + ## Returns the first element of the vector that satisfies the predicate or + `if_missing` if no elements of the vector satisfy it. - For this method to be defined, the elements of the vector must be able to - have the `+` operator used to combine them. + Arguments: + - predicate: A function that takes a list element and returns a boolean + value that says whether that value satisfies the conditions of the + function. + - start: The index to start searching from. If the index is negative, it + is counted from the end of the vector. + - if_missing: Value returned if no element satisfies the predicate. > Example - Compute the sum of all fo the elements in a vector. + Finding a first element of the vector that is larger than 3. - [0, 1, 2].sum - sum : Any ! (Empty_Error | No_Such_Method) - sum self = - result = Panic.recover Any <| self.reduce (+) - result.map_error x->case x of - _ : No_Such_Method -> x - Empty_Error -> x - _ -> Panic.throw x + [1, 2, 3, 4, 5].find (> 3) + find : (Any -> Boolean) -> Integer -> Any -> Any + find self predicate start=0 ~if_missing=(Error.throw Not_Found) = + self_len = self.length + check_start_valid start self_len used_start-> + found = used_start.up_to self_len . find (idx -> (predicate (self.at idx))) + if found.is_nothing then if_missing else self.at found - ## Checks whether a predicate holds for at least one element of this vector. + ## Returns the index of an element in the vector. + Returns Nothing if the element is not found. Arguments: - - predicate: A function that takes a list element and returns a boolean - value that says whether that value satisfies the conditions of the - function. + - element: The element to search for or a predicate function to test for + each element. + - start: The index to start searching from. If the index is negative, it + is counted from the end of the vector. > Example - Check if any element of the list is larger than 3. + Find the index of an element in a vector. - [1, 2, 3, 4, 5].exists (> 3) - exists : (Any -> Boolean) -> Boolean - exists self predicate = - 0.up_to self.length . exists (idx -> (predicate (self.at idx))) + [1, 2, 3].index_of 2 == 1 + index_of : (Any | (Any -> Boolean)) -> Integer -> Integer | Nothing + index_of self element start=0 = + self_len = self.length + check_start_valid start self_len used_start-> + predicate = case element of + _ : Function -> (i -> element (self.at i)) + _ -> (i -> self.at i == element) + used_start.up_to self.length . find if_missing=Nothing predicate - ## Returns the first element of the vector that satisfies the predicate or - if no elements of the vector satisfy the predicate, it throws nothing. + ## Returns the last index of an element in the vector. + Returns `Nothing` if the element is not found. Arguments: - - predicate: A function that takes a list element and returns a boolean - value that says whether that value satisfies the conditions of the - function. + - element: The element to search for or a predicate function to test for + each element. + - start: The index to start searching backwards from. If the index is + negative, it is counted from the end of the vector. > Example - Finding a first element of the list that is larger than 3. + Find the last index of an element in a vector. - [1, 2, 3, 4, 5].find (> 3) - find : (Any -> Boolean) -> Any ! Nothing - find self predicate = - found = 0.up_to self.length . find (idx -> (predicate (self.at idx))) - if found.is_nothing then Error.throw Nothing else self.at found + [1, 2, 3, 1, 2, 3].last_index_of 2 == 4 + last_index_of : (Any | (Any -> Boolean)) -> Integer -> Integer | Nothing + last_index_of self element start=-1 = + self_len = self.length + if self_len == 0 && (start==0 || start==-1) then Nothing else + check_start_valid start self_len used_start-> + predicate = case element of + _ : Function -> (i -> element (self.at i)) + _ -> (i -> self.at i == element) + used_start.down_to -1 . find if_missing=Nothing predicate ## Checks whether a predicate holds for at least one element of self vector. @@ -322,7 +342,8 @@ type Vector a [1, 2, 3, 4, 5].any (> 3) any : (Any -> Boolean) -> Boolean - any self predicate = self.exists predicate + any self predicate = + 0.up_to self.length . any (idx -> (predicate (self.at idx))) ## Checks whether a predicate holds for all elements in this vector. @@ -336,7 +357,7 @@ type Vector a [-1, 1, 5, 8].all (< 0) all : (Any -> Boolean) -> Boolean - all self predicate = self . exists (predicate >> .not) . not + all self predicate = self . any (predicate >> .not) . not ## Checks whether this vector contains a given value as an element. @@ -348,7 +369,7 @@ type Vector a [1, 383, 72, 301].contains 72 contains : Any -> Boolean - contains self elem = self.exists ix-> ix == elem + contains self elem = self.any ix-> ix == elem ## Checks if this vector is empty. @@ -525,12 +546,12 @@ type Vector a ## Applies a function to each element of the vector. - Arguments: - - function: A function to apply 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. + Arguments: + - function: A function to apply to each element of the vector. + > Example Print each element in the vector to standard output. @@ -613,36 +634,60 @@ type Vector a [1] + [2] + : Vector Any -> Vector Any - + self that = - self_len = self.length - arr = Array.new (self_len + that.length) - Array.copy self.to_array 0 arr 0 self_len - Array.copy that.to_array 0 arr self_len that.length - Vector.from_polyglot_array arr - - ## Add `element` to the beginning of `self` vector. + + self that = case that of + _ : Vector -> + self_len = self.length + that_len = that.length + arr = Array.new (self_len + that_len) + Array.copy self.to_array 0 arr 0 self_len + Array.copy that.to_array 0 arr self_len that_len + Vector.from_polyglot_array arr + _ : Array -> self + Vector.from_polyglot_array that + _ -> Error.throw (Type_Error.Error Vector that "that") + + ## Inserts the given item into the vector at the given index. Arguments: - - `element`: An element to add to this vector. + - at: The index at which to insert the item before. + If the index is less than 0, the index will be counted back from the + end. If the index is equal to the length of the Vector, the item will + be appended to the end of the Vector. + - item: The item to insert into the vector. > Example - Add 1 to the start of the vector. - - [2, 3].prepend 1 - prepend : Any -> Vector Any - prepend self element = [element] + self + Insert 'X' into ['a', 'b', 'c'] at different locations: - ## Add `element` to the end of `self` vector. + ['a', 'b', 'c'].insert 1 'X' == ['a', 'X', 'b', 'c'] + ['a', 'b', 'c'].insert -1 'X' == ['a', 'b', 'X', 'c'] + ['a', 'b', 'c'].insert item='X' == ['a', 'b', 'c', 'X'] + insert : Integer -> Any -> Vector ! Index_Out_Of_Bounds + insert self at=self.length item=Nothing = + self_len = self.length + used_index = if at < 0 then self_len + at else at + if used_index < 0 || used_index > self_len then Error.throw (Index_Out_Of_Bounds.Error at self_len+1) else + if used_index == self_len then self + [item] else + if used_index == 0 then [item] + self else + arr = Array.new (self_len + 1) + Array.copy self.to_array 0 arr 0 used_index + Array.copy [item].to_array 0 arr used_index 1 + Array.copy self.to_array used_index arr (used_index + 1) (self_len - used_index) + Vector.from_polyglot_array arr + + ## Removes the item at the given index from the vector. Arguments: - - `element`: An element to add to this vector. - - > Example - Add 3 to the end of the vector. - - [1, 2].append 3 - append : Any -> Vector Any - append self element = self + [element] + - at: The index at which to remove the item. + If the index is less than 0, the index will be counted back from the + end. + remove : Integer -> Any -> Vector + remove self at=-1 = + self_len = self.length + used_index = if at < 0 then self_len + at else at + if used_index >= self_len || used_index < 0 then Error.throw (Index_Out_Of_Bounds.Error at self_len) else + arr = Array.new (self_len - 1) + Array.copy self.to_array 0 arr 0 used_index + Array.copy self.to_array (used_index + 1) arr used_index (self_len - used_index - 1) + Vector.from_polyglot_array arr ## When `self` is a vector of text values, concatenates all the values by interspersing them with `separator`. @@ -758,55 +803,25 @@ type Vector a if self.length >= n then self else self + (Vector.fill n-self.length elem) - ## Get the first element from the vector, or an `Empty_Error` if the vector + ## Get the first element from the vector, or an `Index_Out_Of_Bounds` if the vector is empty. > Example The following code returns 1. - [1, 2, 3, 4].head - head : Any ! Empty_Error - head self = if self.length >= 1 then self.at 0 else Error.throw Empty_Error - - ## Get all elements in the vector except the first. - - > Example - The following code returns [2, 3, 4]. - - [1, 2, 3, 4].tail - tail : Vector ! Empty_Error - tail self = if self.length >= 1 then self.drop (Index_Sub_Range.First 1) else - Error.throw Empty_Error - - ## Get the all elements in the vector except the last. - - > Example - The following code returns [1, 2, 3]. - - [1, 2, 3, 4].init - init : Vector ! Empty_Error - init self = if self.length >= 1 then self.drop (Index_Sub_Range.Last 1) else Error.throw Empty_Error + [1, 2, 3, 4].first + first : Any ! Index_Out_Of_Bounds + first self = self.at 0 - ## Get the last element of the vector, or an `Empty_Error` if the vector is + ## Get the last element of the vector, or an `Index_Out_Of_Bounds` if the vector is empty. > Example The following code returns 4. [1, 2, 3, 4].last - last : Vector ! Empty_Error - last self = if self.length >= 1 then self.at (self.length-1) else - Error.throw Empty_Error - - ## Get the first element from the vector, or an `Empty_Error` if the vector - is empty. - - > Example - The following code returns 1. - - [1, 2, 3, 4].first - first : Vector ! Empty_Error - first self = self.head + last : Any ! Index_Out_Of_Bounds + last self = self.at -1 ## Get the second element from the vector, or a `Index_Out_Of_Bounds` if the vector doesn't have a second element. @@ -817,25 +832,17 @@ type Vector a The following code returns 2. [1, 2, 3, 4].second - second : Vector ! Index_Out_Of_Bounds + second : Any ! Index_Out_Of_Bounds second self = self.at 1 - ## Get all elements in the vector except the first. - - > Example - The following code returns [2, 3, 4]. - [1, 2, 3, 4].rest - rest : Vector ! Empty_Error - rest self = self.tail - ## Sort the Vector. Arguments: + - order: The order in which the vector elements are sorted. - on: A projection from the element type to the value of that element being sorted on. - by: A function that compares the result of applying `on` to two elements, returning an Ordering to compare them. - - order: The order in which the vector elements are sorted. By default, elements are sorted in ascending order, using the comparator `compare_to`. A custom comparator may be passed to the sort function. @@ -868,12 +875,9 @@ type Vector a > Example Sorting a vector of `Pair`s on the first element, descending. - [Pair 1 2, Pair -1 8].sort (_.first) (order = Sort_Direction.Descending) - sort : (Any -> Any) -> (Any -> Any -> Ordering) -> Sort_Direction -> Vector Any ! Incomparable_Values - sort self (on = x -> x) (by = (_.compare_to _)) (order = Sort_Direction.Ascending) = - ## As we want to account for both custom projections and custom - comparisons we need to construct a comparator for internal use that - does both. + [Pair 1 2, Pair -1 8].sort Sort_Direction.Descending (_.first) + sort : Sort_Direction -> (Any -> Any) -> (Any -> Any -> Ordering) -> Vector Any ! Incomparable_Values + sort self (order = Sort_Direction.Ascending) (on = x -> x) (by = (_.compare_to _)) = comp_ascending l r = by (on l) (on r) comp_descending l r = by (on r) (on l) compare = if order == Sort_Direction.Ascending then comp_ascending else @@ -927,6 +931,11 @@ type Vector a existing.insert key True if result.is_error then result else builder.to_vector + ## UNSTABLE + Returns the Vector as a Vector. + to_vector : Vector + to_vector self = self + ## UNSTABLE Converts the vector to a list with the same elements. to_list : List @@ -1064,7 +1073,7 @@ type Builder Panic.catch IndexOutOfBoundsException (self.java_builder.get actual_index) _-> Error.throw (Index_Out_Of_Bounds.Error index self.length) - ## Get the first element from the vector, or an `Empty_Error` if the vector + ## Get the first element from the vector, or an `Index_Out_Of_Bounds` if the vector is empty. > Example @@ -1074,7 +1083,7 @@ type Builder first : Vector ! Index_Out_Of_Bounds first self = self.at 0 - ## Get the last element of the vector, or an `Empty_Error` if the vector is + ## Get the last element of the vector, or an `Index_Out_Of_Bounds` if the vector is empty. > Example @@ -1090,9 +1099,9 @@ type Builder - predicate: A function that takes a list element and returns a boolean that says whether that value satisfies the conditions of the function. - exists : (Any -> Boolean) -> Boolean - exists self predicate = - 0.up_to self.length . exists (idx -> (predicate (self.java_builder.get idx))) + any : (Any -> Boolean) -> Boolean + any self predicate = + 0.up_to self.length . any (idx -> (predicate (self.java_builder.get idx))) ## Converts this builder to a vector containing all the appended elements. @@ -1154,3 +1163,9 @@ slice_many_ranges vector ranges = descriptor.each ix-> builder.append (vector.at ix) builder.to_vector + +## PRIVATE +check_start_valid start length function = + used_start = if start < 0 then start + length else start + if used_start < 0 || used_start > length then Error.throw (Index_Out_Of_Bounds.Error start length+1) else + function used_start diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Error/Common.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Error/Common.enso index 4cc280bcc353..bfe8c633ccc5 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Error/Common.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Error/Common.enso @@ -1,6 +1,9 @@ import project.Data.Text.Text import project.Meta +## An error indicating that no value was found. +type Not_Found + @Builtin_Type type Index_Out_Of_Bounds ## PRIVATE diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Function.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Function.enso index ed22a6612bc6..5a3ba1587846 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Function.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Function.enso @@ -63,4 +63,4 @@ curry f = x -> y -> f [x, y] # uncurry : (a -> b -> c) -> ([a, b] -> c) uncurry : (Any -> Any -> Any) -> (Vector Any -> Any) -uncurry f = (pair -> f pair.head pair.second) +uncurry f = (pair -> f pair.first pair.second) diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Panic.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Panic.enso index c467153e6df6..53f916833137 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Panic.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Panic.enso @@ -154,7 +154,7 @@ type Panic _ : Vector -> expected_types _ -> [expected_types] Panic.catch Any action caught_panic-> - is_matched = types_to_check.exists typ-> + is_matched = types_to_check.any typ-> caught_panic.payload.is_a typ case is_matched of True -> caught_panic.convert_to_dataflow_error diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Random.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Random.enso index 9589ed4bc62f..d2ad89f118de 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Random.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Random.enso @@ -1,8 +1,13 @@ import project.Any.Any +import project.Data.Boolean.Boolean import project.Data.Numbers.Integer +import project.Data.Numbers.Decimal import project.Data.Vector.Vector +import project.Error.Error +import project.Error.Illegal_Argument.Illegal_Argument import project.System +polyglot java import java.lang.Integer as Java_Integer polyglot java import java.util.Random as Java_Random polyglot java import org.enso.base.Random_Utils @@ -22,6 +27,32 @@ type Random_Number_Generator ## A random number generator. Value java_random + ## Gets the next random Boolean. + boolean : Decimal + boolean self = + self.java_random.nextBoolean + + ## Gets the next random Decimal between 0 and 1. + decimal : Decimal + decimal self = + self.java_random.nextDouble + + ## Gets the next random Decimal from a normal distribution with mean 0 and std-dev 1. + gaussian : Decimal + gaussian self = + self.java_random.nextGaussian + + ## Gets the next random integer between min (inclusive) and max (exclusive). + + Arguments: + - min: the minimum value (inclusive) of the random integer. + - max: the maximum value (exclusive) of the random integer. + integer : Integer -> Integer -> Integer + integer self min=0 max=100 = + range = max - min + if range < Java_Integer.MAX_VALUE then min + (self.java_random.nextInt range) else + Error.throw (Illegal_Argument.Error "Currently only integer ranges of up to 2^31-1 are supported.") + ## Returns a new vector containing a random sample of the input vector, without replacement. diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/System/File_Format.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/System/File_Format.enso index 7bc730e580c0..5f17bb410ba5 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/System/File_Format.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/System/File_Format.enso @@ -77,8 +77,8 @@ type Plain_Text_Format parts = content_type.split ";" . map .trim case parts.first of "text/plain" -> - charset_part = parts.find (x->x.starts_with "charset=") - encoding = if charset_part.is_error then Encoding.utf_8 else + charset_part = parts.find if_missing=Nothing (x->x.starts_with "charset=") + encoding = if charset_part.is_nothing then Encoding.utf_8 else parsed = Encoding.from_name (charset_part.drop 8) if parsed.is_error then Encoding.utf_8 else parsed Plain_Text_Format.Plain_Text encoding diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Column.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Column.enso index 102e73484e56..cc0e153cce57 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Column.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Column.enso @@ -624,7 +624,7 @@ type Column Arguments: - order: Specifies the default sort order for this operation. - missing_last: Specifies the default placement of missing values when - compared to non-missing ones. Note thet this argument is independent + compared to non-missing ones. Note that this argument is independent from `order`, i.e. missing values will always be sorted according to this rule, ignoring the ascending / descending setting. @@ -634,7 +634,7 @@ type Column > Example Sorting `column` in descending order. - column.sort order=Sort_Direction.Descending + column.sort Sort_Direction.Descending sort : Sort_Direction -> Column sort self order=Sort_Direction.Ascending = self.to_table.order_by (Sort_Column_Selector.By_Column [Sort_Column.Column self order]) . at self.name diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Table.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Table.enso index ceb3cdd839f1..cb143ae18dcf 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Table.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Data/Table.enso @@ -100,7 +100,7 @@ type Table at self selector=0 = case selector of _ : Integer -> self.make_column (self.internal_columns.at selector) _ : Text -> - internal_column = self.internal_columns.find (p -> p.name == selector) . map_error (_ -> No_Such_Column.Error selector) + internal_column = self.internal_columns.find if_missing=(Error.throw (No_Such_Column.Error selector)) (p -> p.name == selector) self.make_column internal_column ## Returns the number of columns in the table. @@ -271,7 +271,7 @@ type Table case-sensitive ascending order based on the `Text.compare_to` operator. Arguments: - - direction: Whether sorting should be in ascending or descending order. + - order: Whether sorting should be in ascending or descending order. - text_ordering: The sort methodology to use. > Example @@ -289,8 +289,8 @@ type Table table.reorder_columns Sort_Direction.Descending sort_columns : Sort_Direction -> Text_Ordering -> Table - sort_columns self direction=Sort_Direction.Ascending text_ordering=Text_Ordering.Default = - new_columns = Table_Helpers.sort_columns internal_columns=self.internal_columns direction text_ordering + sort_columns self order=Sort_Direction.Ascending text_ordering=Text_Ordering.Default = + new_columns = Table_Helpers.sort_columns internal_columns=self.internal_columns order text_ordering self.updated_columns new_columns ## Returns a new table with the columns renamed based on either a mapping @@ -512,7 +512,7 @@ type Table _ : Text -> self.evaluate column _ -> column new_col = Internal_Column.Value name resolved.sql_type resolved.expression - replace = self.internal_columns.exists (c -> c.name == name) + replace = self.internal_columns.any (c -> c.name == name) case replace of True -> new_cols = self.internal_columns.map (c -> if c.name == name then new_col else c) @@ -554,7 +554,8 @@ type Table rows self max_rows=1000 = self.read max_rows=max_rows . rows - ## Sorts the rows of the table according to the specified columns and order. + ## ALIAS sort + Sorts the rows of the table according to the specified columns and order. Arguments: - columns: The columns and order to sort the table. @@ -911,7 +912,8 @@ type Table filter_blank_rows self when_any=False treat_nans_as_blank=False = Table_Helpers.filter_blank_rows self when_any treat_nans_as_blank - ## Returns the amount of rows in this table. + ## ALIAS count + Returns the amount of rows in this table. row_count : Integer row_count self = if self.internal_columns.is_empty then 0 else expr = SQL_Expression.Operation "COUNT_ROWS" [] diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Base_Generator.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Base_Generator.enso index 39afe2a5d30f..3d6a3e74c09f 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Base_Generator.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Base_Generator.enso @@ -221,7 +221,7 @@ make_is_in arguments = case arguments.length of 1 -> code 'FALSE' . paren _ -> expr = arguments.first - list = arguments.tail + list = arguments.drop 1 is_in = expr ++ " IN (" ++ (SQL.join ", " list) ++ ")" ## We ensure that even `NULL IN (...)` is coalesced to False, so that negation will work as expected. diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Pgpass.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Pgpass.enso index 7b026f908d32..ae3822edb1e6 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Pgpass.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Pgpass.enso @@ -26,9 +26,9 @@ read host port database username=Nothing = pgpass_file = locate if pgpass_file.is_nothing || (verify pgpass_file . not) then [] else entries = parse_file pgpass_file - found = entries.find entry-> + found = entries.find if_missing=Nothing entry-> entry.matches host port database username - case found.catch Nothing of + case found of Nothing -> [] entry -> [Pair.new 'user' entry.username, Pair.new 'password' entry.password] diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Postgres_Dialect.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Postgres_Dialect.enso index 2693e1195c3e..54774b29414c 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Postgres_Dialect.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Postgres_Dialect.enso @@ -188,8 +188,8 @@ first_last_aggregators = make_first_aggregator reverse ignore_null args = if args.length < 2 then Error.throw (Illegal_State.Error "Insufficient number of arguments for the operation.") else - result_expr = args.head - order_bys = args.tail + result_expr = args.first + order_bys = args.drop 1 filter_clause = if ignore_null.not then "" else code " FILTER (WHERE " ++ result_expr.paren ++ " IS NOT NULL)" diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/SQLite/SQLite_Dialect.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/SQLite/SQLite_Dialect.enso index b78e2c626f79..1c9636dc7d41 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/SQLite/SQLite_Dialect.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/SQLite/SQLite_Dialect.enso @@ -194,8 +194,8 @@ first_last_aggregators = ## PRIVATE window_aggregate window_type ignore_null args = if args.length < 2 then Error.throw (Illegal_State.Error "Insufficient number of arguments for the operation.") else - result_expr = args.head - order_exprs = args.tail + result_expr = args.first + order_exprs = args.drop 1 filter_clause = if ignore_null.not then code "" else code " FILTER (WHERE " ++ result_expr.paren ++ " IS NOT NULL)" diff --git a/distribution/lib/Standard/Google_Api/0.0.0-dev/src/Main.enso b/distribution/lib/Standard/Google_Api/0.0.0-dev/src/Main.enso index bd6bda9ee899..a5b7fd255627 100644 --- a/distribution/lib/Standard/Google_Api/0.0.0-dev/src/Main.enso +++ b/distribution/lib/Standard/Google_Api/0.0.0-dev/src/Main.enso @@ -40,7 +40,7 @@ type Spreadsheets request = self.java_service.spreadsheets.values.get sheet_id sheet_range . setMajorDimension 'COLUMNS' . setValueRenderOption 'UNFORMATTED_VALUE' response = request.execute values = Vector.from_polyglot_array response.getValues . map Vector.Vector - columned = values.map v-> [v.head, v.tail] + columned = values.map v-> [v.first, v.drop 1] Table.new columned ## Initializes the Google services instance using the given credentials file. diff --git a/distribution/lib/Standard/Searcher/0.0.0-dev/src/Data_Science/Aggregate.enso b/distribution/lib/Standard/Searcher/0.0.0-dev/src/Data_Science/Aggregate.enso index 1f89e4101990..f80a04330640 100644 --- a/distribution/lib/Standard/Searcher/0.0.0-dev/src/Data_Science/Aggregate.enso +++ b/distribution/lib/Standard/Searcher/0.0.0-dev/src/Data_Science/Aggregate.enso @@ -1,6 +1,6 @@ ## With your data in the state that you want, the next step is to pull useful summaries from it to give you insight. This is the process of _aggregation_ - or _summarisation_. + or _summarization_. Enso provides robust facilities for getting aggregate results from your data, all built on a flexible foundation of grouping. @@ -23,13 +23,10 @@ Compute the maximum value of a column, the minimum value, the sum of its values, and its mean, and return these in a vector. + from Standard.Table import all import Standard.Examples example_aggregate = column = Examples.integer_column - max = column.max - min = column.min - sum = column.sum - mean = column.mean - [max, min, sum, mean] - + as_table = column.to_table + aggregate = as_table.aggregate [Aggregate_Column.Minimum, Aggregate_Column.Maximum, Aggregate_Column.Sum, Aggregate_Column.Average] diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Aggregate_Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Aggregate_Column.enso index 7c07ea9eaf86..e09dcb618aeb 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Aggregate_Column.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Aggregate_Column.enso @@ -24,7 +24,7 @@ type Aggregate_Column Column object) to count across. - name: name of new column. - ignore_nothing: if all values are Nothing won't be included. - Count_Distinct (columns:Column|Text|Integer|Column_Selector) (new_name:Text|Nothing=Nothing) (ignore_nothing:Boolean=False) + Count_Distinct (columns:Column|Text|Integer|Column_Selector=0) (new_name:Text|Nothing=Nothing) (ignore_nothing:Boolean=False) ## ALIAS Count_Not_Null @@ -34,7 +34,7 @@ type Aggregate_Column Arguments: - columns: column (specified by name, index or Column object) to count. - name: name of new column. - Count_Not_Nothing (column:Column|Text|Integer) (new_name:Text|Nothing=Nothing) + Count_Not_Nothing (column:Column|Text|Integer=0) (new_name:Text|Nothing=Nothing) ## ALIAS Count_Null, Count_Missing @@ -44,7 +44,7 @@ type Aggregate_Column Arguments: - column: column (specified by name, index or Column object) to count. - name: name of new column. - Count_Nothing (column:Column|Text|Integer) (new_name:Text|Nothing=Nothing) + Count_Nothing (column:Column|Text|Integer=0) (new_name:Text|Nothing=Nothing) ## Creates a new column with the count of not `Nothing` (null) and non-empty ("") values of the column within each group. If no rows, evaluates to 0. @@ -52,7 +52,7 @@ type Aggregate_Column Arguments: - column: column (specified by name, index or Column object) to count. - name: name of new column. - Count_Not_Empty (column:Column|Text|Integer) (new_name:Text|Nothing=Nothing) + Count_Not_Empty (column:Column|Text|Integer=0) (new_name:Text|Nothing=Nothing) ## Creates a new column with the count of `Nothing` (null) or empty ("") text values of the column within each group. If no rows, evaluates to 0. @@ -60,7 +60,7 @@ type Aggregate_Column Arguments: - column: column (specified by name, index or Column object) to count. - name: name of new column. - Count_Empty (column:Column|Text|Integer) (new_name:Text|Nothing=Nothing) + Count_Empty (column:Column|Text|Integer=0) (new_name:Text|Nothing=Nothing) ## Creates a new column with the sum of values (ignoring missing values) of the column within each group. If no rows, evaluates to `Nothing`. @@ -68,7 +68,7 @@ type Aggregate_Column Arguments: - column: column (specified by name, index or Column object) to total. - name: name of new column. - Sum (column:Column|Text|Integer) (new_name:Text|Nothing=Nothing) + Sum (column:Column|Text|Integer=0) (new_name:Text|Nothing=Nothing) ## Creates a new column with the mean of values (ignoring missing values) of the column within each group. If no rows, evaluates to `Nothing`. @@ -76,7 +76,7 @@ type Aggregate_Column Arguments: - column: column (specified by name, index or Column object) to average. - name: name of new column. - Average (column:Column|Text|Integer) (new_name:Text|Nothing=Nothing) + Average (column:Column|Text|Integer=0) (new_name:Text|Nothing=Nothing) ## Creates a new column with the median of values (ignoring missing values) of the column within each group. If no rows, evaluates to `Nothing`. @@ -85,7 +85,7 @@ type Aggregate_Column - column: column (specified by name, index or Column object) to calculate median on. - name: name of new column. - Median (column:Column|Text|Integer) (new_name:Text|Nothing=Nothing) + Median (column:Column|Text|Integer=0) (new_name:Text|Nothing=Nothing) ## Creates a new column with the median of values (ignoring missing values) of the column within each group. If no rows, evaluates to `Nothing`. @@ -95,7 +95,7 @@ type Aggregate_Column - column: column (specified by name, index or Column object) to compute percentile. - name: name of new column. - Percentile (percentile:Decimal) (column:Column|Text|Integer) (new_name:Text|Nothing=Nothing) + Percentile (percentile:Decimal=0.5) (column:Column|Text|Integer=0) (new_name:Text|Nothing=Nothing) ## Creates a new column with the mode of values (ignoring missing values) of the column within each group. If no rows, evaluates to `Nothing`. @@ -104,7 +104,7 @@ type Aggregate_Column - column: column (specified by name, index or Column object) to find the most common value. - name: name of new column. - Mode (column:Column|Text|Integer) (new_name:Text|Nothing=Nothing) + Mode (column:Column|Text|Integer=0) (new_name:Text|Nothing=Nothing) ## Creates a new column with the standard deviation of values (ignoring missing values) of the column within each group. If no rows, evaluates to @@ -115,7 +115,7 @@ type Aggregate_Column standard deviation. - name: name of new column. - population: specifies if group is a sample or the population - Standard_Deviation (column:Column|Text|Integer) (new_name:Text|Nothing=Nothing) (population:Boolean=False) + Standard_Deviation (column:Column|Text|Integer=0) (new_name:Text|Nothing=Nothing) (population:Boolean=False) ## Creates a new column with the values concatenated together. `Nothing` values will become an empty string. If no rows, evaluates to `Nothing`. @@ -129,7 +129,7 @@ type Aggregate_Column - suffix: added at the end of the result. - quote_char: character used to quote the values if the value is `Empty` or contains the separator. - Concatenate (column:Column|Text|Integer) (new_name:Text|Nothing=Nothing) (separator:Text="") (prefix:Text="") (suffix:Text="") (quote_char:Text="") + Concatenate (column:Column|Text|Integer=0) (new_name:Text|Nothing=Nothing) (separator:Text="") (prefix:Text="") (suffix:Text="") (quote_char:Text="") ## Creates a new column with the first value in each group. If no rows, evaluates to `Nothing`. @@ -142,7 +142,7 @@ type Aggregate_Column not missing value returned. - order_by: required for database tables. Specifies how to order the results within the group. - First (column:Column|Text|Integer) (new_name:Text|Nothing=Nothing) (ignore_nothing:Boolean=True) (order_by:Sort_Column_Selector|Nothing=Nothing) + First (column:Column|Text|Integer=0) (new_name:Text|Nothing=Nothing) (ignore_nothing:Boolean=True) (order_by:Sort_Column_Selector|Nothing=Nothing) ## Creates a new column with the last value in each group. If no rows, evaluates to `Nothing`. @@ -155,7 +155,7 @@ type Aggregate_Column not missing value returned. - order_by: required for database tables. Specifies how to order the results within the group. - Last (column:Column|Text|Integer) (new_name:Text|Nothing=Nothing) (ignore_nothing:Boolean=True) (order_by:Sort_Column_Selector|Nothing=Nothing) + Last (column:Column|Text|Integer=0) (new_name:Text|Nothing=Nothing) (ignore_nothing:Boolean=True) (order_by:Sort_Column_Selector|Nothing=Nothing) ## Creates a new column with the maximum value in each group. If no rows, evaluates to `Nothing`. @@ -164,7 +164,7 @@ type Aggregate_Column - column: column (specified by name, index or Column object) to find maximum. - name: name of new column. - Maximum (column:Column|Text|Integer) (new_name:Text|Nothing=Nothing) + Maximum (column:Column|Text|Integer=0) (new_name:Text|Nothing=Nothing) ## Creates a new column with the maximum value in each group. If no rows, evaluates to `Nothing`. @@ -173,7 +173,7 @@ type Aggregate_Column - column: column (specified by name, index or Column object) to find minimum. - name: name of new column. - Minimum (column:Column|Text|Integer) (new_name:Text|Nothing=Nothing) + Minimum (column:Column|Text|Integer=0) (new_name:Text|Nothing=Nothing) ## Creates a new column with the shortest text in each group. If no rows, evaluates to `Nothing`. @@ -182,7 +182,7 @@ type Aggregate_Column - column: column (specified by name, index or Column object) to find shortest value. - name: name of new column. - Shortest (column:Column|Text|Integer) (new_name:Text|Nothing=Nothing) + Shortest (column:Column|Text|Integer=0) (new_name:Text|Nothing=Nothing) ## Creates a new column with the longest text in each group. If no rows, evaluates to `Nothing`. @@ -191,4 +191,4 @@ type Aggregate_Column - column: column (specified by name, index or Column object) to find longest value. - name: name of new column. - Longest (column:Column|Text|Integer) (new_name:Text|Nothing=Nothing) + Longest (column:Column|Text|Integer=0) (new_name:Text|Nothing=Nothing) diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso index bd1a49374bd5..a0fcb68880e6 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Column.enso @@ -1096,8 +1096,8 @@ type Column compared to non-missing ones. Note that this argument is independent from `order`, i.e. missing values will always be sorted according to this rule, ignoring the ascending / descending setting. - - comparator: function taking two items in this column and returning - an ordering. If specified, it is used instead of the natural + - by: function taking two items in this column and returning an + ordering. If specified, it is used instead of the natural (`.compare_to`) ordering. > Example @@ -1114,7 +1114,7 @@ type Column import Standard.Examples example_sort = - Examples.integer_column.sort order=Sort_Direction.Descending missing_last=False + Examples.integer_column.sort Sort_Direction.Descending missing_last=False > Example Sorting `column` in ascending order, using a custom comparator @@ -1124,13 +1124,13 @@ type Column example_sort = my_comparator a b = a.abs.compare_to b.abs - Examples.decimal_column.sort comparator=my_comparator + Examples.decimal_column.sort by=my_comparator sort : Sort_Direction -> Boolean -> (Any -> Any -> Ordering) | Nothing -> Column - sort self order=Sort_Direction.Ascending missing_last=True comparator=Nothing = + sort self order=Sort_Direction.Ascending missing_last=True by=Nothing = order_bool = case order of Sort_Direction.Ascending -> True Sort_Direction.Descending -> False - java_cmp = Comparator.new comparator + java_cmp = Comparator.new by rule = OrderBuilder.OrderRule.new self.java_column java_cmp order_bool missing_last mask = OrderBuilder.buildOrderMask [rule].to_array new_col = self.java_column.applyMask mask @@ -1168,7 +1168,7 @@ type Column Returns the first element in the column, if it exists. If the column is empty, this method will return a dataflow error - containing an `Empty_Error`. + containing an `Index_Out_Of_Bounds`. > Example Get the first element of a column. @@ -1176,15 +1176,15 @@ type Column import Standard.Examples example_first = Examples.integer_column.first - first : Any ! Empty_Error - first self = self.at 0 . catch Index_Out_Of_Bounds.Error (_ -> Error.throw Empty_Error) + first : Any ! Index_Out_Of_Bounds + first self = self.at 0 ## UNSTABLE Returns the last element in the column, if it exists. If the column is empty, this method will return a dataflow error - containing an `Empty_Error`. + containing an `Index_Out_Of_Bounds`. > Example Get the last element of a column. @@ -1192,8 +1192,8 @@ type Column import Standard.Examples example_last = Examples.integer_column.last - last : Any ! Empty_Error - last self = self.at (self.length - 1) . catch Index_Out_Of_Bounds.Error (_ -> Error.throw Empty_Error) + last : Any ! Index_Out_Of_Bounds + last self = self.at (self.length - 1) ## UNSTABLE @@ -1230,16 +1230,6 @@ type Column var_args_functions : Vector var_args_functions = ['is_in', 'coalesce', 'min', 'max'] -## UNSTABLE - - An error for when the column contains no elements. -type Empty_Error - ## PRIVATE - - Pretty prints the empty column error. - to_display_text : Text - to_display_text self = "The column is empty." - ## PRIVATE Folds the vectorized operation over the provided column and values. When more diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Table.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Table.enso index ffff670190a8..073e6e5d30cf 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Table.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Data/Table.enso @@ -372,7 +372,7 @@ type Table `Text`. Arguments: - - direction: Whether sorting should be in ascending or descending order. + - order: Whether sorting should be in ascending or descending order. - text_ordering: The sort methodology to use. > Example @@ -390,8 +390,8 @@ type Table table.reorder_columns Sort_Direction.Descending sort_columns : Sort_Direction -> Text_Ordering -> Table - sort_columns self direction=Sort_Direction.Ascending text_ordering=Text_Ordering.Default = - new_columns = Table_Helpers.sort_columns internal_columns=self.columns direction text_ordering + sort_columns self order=Sort_Direction.Ascending text_ordering=Text_Ordering.Default = + new_columns = Table_Helpers.sort_columns internal_columns=self.columns order text_ordering Table.new new_columns ## Returns a new table with the columns renamed based on either a mapping @@ -516,7 +516,8 @@ type Table problems = java_table.getProblems Java_Problems.parse_aggregated_problems problems - ## Sorts the rows of the table according to the specified columns and order. + ## ALIAS sort + Sorts the rows of the table according to the specified columns and order. Arguments: - columns: The columns and order to sort the table. @@ -686,7 +687,7 @@ type Table if matching_input.length == 0 then Nothing else if matching_input.length == 1 then matching_input.first.datatype else first_type = matching_input.first.datatype - ambiguous = matching_input.exists s-> s.datatype != first_type + ambiguous = matching_input.any s-> s.datatype != first_type problem_builder.append (Duplicate_Type_Selector.Error column.name ambiguous) if ambiguous then Nothing else first_type @@ -703,7 +704,7 @@ type Table if valid.not then invalid_indices.append selector _ : Text -> - found = columns.exists col-> col.name == selector + found = columns.any col-> col.name == selector if found.not then missing_columns.append selector if missing_columns.is_empty.not then @@ -893,7 +894,7 @@ type Table > Example Take rows from the top of the table as long as their values sum to 10. - table.take (While row-> row.to_vector.sum == 10) + table.take (While row-> row.to_vector.compute Statistic.Sum == 10) take : (Index_Sub_Range | Range | Integer) -> Table take self range=(First 1) = Index_Sub_Range_Module.take_helper self.row_count self.rows.at self.slice (slice_ranges self) range @@ -915,7 +916,7 @@ type Table > Example Drop rows from the top of the table as long as their values sum to 10. - table.drop (While row-> row.to_vector.sum == 10) + table.drop (While row-> row.to_vector.compute Statistic.Sum == 10) drop : (Index_Sub_Range | Range | Integer) -> Table drop self range=(First 1) = Index_Sub_Range_Module.drop_helper self.row_count self.rows.at self.slice (slice_ranges self) range @@ -1097,7 +1098,8 @@ type Table filter_blank_rows self when_any=False treat_nans_as_blank=False = Table_Helpers.filter_blank_rows self when_any treat_nans_as_blank - ## Returns the number of rows in this table. + ## ALIAS count + Returns the number of rows in this table. > Example Count the number of rows in the table. @@ -1398,16 +1400,6 @@ type Table columns_helper self = Table_Helpers.Table_Column_Helper.Value self.columns (x->x) self (x->x) -## UNSTABLE - - An error returned when the table contains no rows. -type Empty_Error - ## PRIVATE - - Pretty prints the empty table error. - to_display_text : Text - to_display_text self = "The table is empty." - ## PRIVATE Ensures that the `txt` has at least `len` characters by appending spaces at diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Delimited/Delimited_Format.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Delimited/Delimited_Format.enso index eb615047ee79..b08fa6139d04 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Delimited/Delimited_Format.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Delimited/Delimited_Format.enso @@ -62,8 +62,8 @@ type Delimited_Format for_web content_type _ = parts = content_type.split ";" . map .trim - charset_part = parts.find (x->x.starts_with "charset=") - encoding = if charset_part.is_error then Encoding.utf_8 else + charset_part = parts.find if_missing=Nothing (x->x.starts_with "charset=") + encoding = if charset_part.if_nothing then Encoding.utf_8 else parsed = Encoding.from_name (charset_part.drop 8) if parsed.is_error then Encoding.utf_8 else parsed diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Delimited/Delimited_Reader.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Delimited/Delimited_Reader.enso index a3c11d970e5c..3975d3957409 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Delimited/Delimited_Reader.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Delimited/Delimited_Reader.enso @@ -193,10 +193,10 @@ newline_at_eof file encoding = newline_bytes = newlines.map (x-> x.bytes encoding Report_Error) most_bytes = newline_bytes.map .length . compute Statistic.Maximum file_last_bytes = file.read_last_bytes most_bytes - result = newlines.zip newline_bytes . find pair-> + result = newlines.zip newline_bytes . find if_missing=[Nothing] pair-> bytes = pair.second bytes == (file_last_bytes.take (Last bytes.length)) - result.first . catch Nothing + result.first ## PRIVATE handle_parsing_failure = diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Table_Helpers.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Table_Helpers.enso index 2d06350dff9a..2702dcf75941 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Table_Helpers.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Internal/Table_Helpers.enso @@ -170,7 +170,7 @@ type Table_Column_Helper modified_table = blanks.fold (self.table.select_columns [] on_problems=Problem_Behavior.Ignore) table-> blanks_col-> table.set blanks_col.name blanks_col # Maximum is equivalent to Exists and Minimum is equivalent to Forall. - col_aggregate = if when_any then Maximum else Minimum + col_aggregate = if when_any then Maximum _ else Minimum _ aggregates = blanks.map blanks_col-> col_aggregate blanks_col.name result = self.materialize <| Panic.rethrow <| modified_table.aggregate aggregates on_problems=Problem_Behavior.Report_Error @@ -299,10 +299,10 @@ rename_columns internal_columns mapping on_problems = Arguments: - internal_columns: A list of all columns in a table. - - direction: Whether sorting should be in ascending or descending order. + - order: Whether sorting should be in ascending or descending order. - text_ordering: The sort methodology to use. sort_columns : Vector -> Sort_Direction -> Text_Ordering -> Vector -sort_columns internal_columns direction text_ordering = +sort_columns internal_columns order text_ordering = case_sensitivity = text_ordering.case_sensitivity.if_nothing Case_Sensitivity.Sensitive mapper = case case_sensitivity of Case_Sensitivity.Sensitive -> _.name @@ -311,7 +311,7 @@ sort_columns internal_columns direction text_ordering = comparator = case text_ordering.sort_digits_as_numbers of True -> Natural_Order.compare False -> .compare_to - internal_columns.sort on=mapper by=comparator order=direction + internal_columns.sort order=order on=mapper by=comparator ## PRIVATE Converts the generic `No_Matches_Found` error to a more specific diff --git a/distribution/lib/Standard/Visualization/0.0.0-dev/src/Helpers.enso b/distribution/lib/Standard/Visualization/0.0.0-dev/src/Helpers.enso index dbc1098278e0..8154843e321d 100644 --- a/distribution/lib/Standard/Visualization/0.0.0-dev/src/Helpers.enso +++ b/distribution/lib/Standard/Visualization/0.0.0-dev/src/Helpers.enso @@ -187,7 +187,7 @@ Array.to_default_visualization_data self = - text: the case-insensitive name of the searched column. Table.lookup_ignore_case : Text -> Column ! Nothing Table.lookup_ignore_case self name = - self.columns.find <| col-> + self.columns.find if_missing=(Error.throw Nothing) <| col-> col.name.equals_ignore_case name ## UNSTABLE diff --git a/distribution/lib/Standard/Visualization/0.0.0-dev/src/Histogram.enso b/distribution/lib/Standard/Visualization/0.0.0-dev/src/Histogram.enso index eff981337d6f..307c11d94c97 100644 --- a/distribution/lib/Standard/Visualization/0.0.0-dev/src/Histogram.enso +++ b/distribution/lib/Standard/Visualization/0.0.0-dev/src/Histogram.enso @@ -7,7 +7,7 @@ import project.Helpers Get first numeric column of the table. Table.first_numeric : Table -> Column ! Nothing -Table.first_numeric self = self.columns.find _.is_numeric +Table.first_numeric self = self.columns.find if_missing=(Error.throw Nothing) _.is_numeric ## PRIVATE diff --git a/distribution/lib/Standard/Visualization/0.0.0-dev/src/Scatter_Plot.enso b/distribution/lib/Standard/Visualization/0.0.0-dev/src/Scatter_Plot.enso index c7d710c9316d..3ce8c4b359e6 100644 --- a/distribution/lib/Standard/Visualization/0.0.0-dev/src/Scatter_Plot.enso +++ b/distribution/lib/Standard/Visualization/0.0.0-dev/src/Scatter_Plot.enso @@ -73,7 +73,7 @@ type Point_Data is_good_enough c = c.is_numeric && c.name != x_column.name is_good c = is_good_enough c && (self.is_recognized c).not - candidates.find is_good . catch_ <| candidates.find is_good_enough + candidates.find if_missing=(Error.throw Nothing) is_good . catch_ <| candidates.find is_good_enough _ -> Error.throw No_Fallback_Column ## PRIVATE diff --git a/distribution/lib/Standard/Visualization/0.0.0-dev/src/Table/Visualization.enso b/distribution/lib/Standard/Visualization/0.0.0-dev/src/Table/Visualization.enso index 2636417cb91b..48f7fac15284 100644 --- a/distribution/lib/Standard/Visualization/0.0.0-dev/src/Table/Visualization.enso +++ b/distribution/lib/Standard/Visualization/0.0.0-dev/src/Table/Visualization.enso @@ -21,42 +21,44 @@ import project.Helpers In case of Database backed data, it materializes a fragment of the data. prepare_visualization : Any -> Integer -> Text -prepare_visualization x max_rows=1000 = Helpers.recover_errors <| case x of - _ : Dataframe_Table -> - dataframe = x.take (First max_rows) - all_rows_count = x.row_count - included_rows = dataframe.row_count - index = Dataframe_Column.from_vector "" (Vector.new included_rows i->i) - - ## Workaround so that the JS String is converted to a Text - https://www.pivotaltracker.com/story/show/184061302 - "" + make_json dataframe [index] all_rows_count - - _ : Database_Table -> - df = x.read max_rows - all_rows_count = x.row_count - - ## Workaround so that the JS String is converted to a Text - https://www.pivotaltracker.com/story/show/184061302 - "" + make_json df [] all_rows_count - - # We display columns as 1-column tables. - _ : Dataframe_Column -> - prepare_visualization x.to_table max_rows - _ : Database_Column -> - prepare_visualization x.to_table max_rows - - # TODO [RW] Should we truncate Vectors? - # We also visualize Vectors and arrays - _ : Vector -> - truncated = x.take (First max_rows) - JS_Object.from_pairs [["json", truncated], ["all_rows_count", x.length]] . to_text - _ : Array -> - prepare_visualization (Vector.from_polyglot_array x) max_rows - - # Anything else will be visualized with the JSON or matrix visualization - _ -> - JS_Object.from_pairs [["json", x]] . to_text +prepare_visualization y max_rows=1000 = Helpers.recover_errors <| + x = Warning.set y [] + case x of + _ : Dataframe_Table -> + dataframe = x.take (First max_rows) + all_rows_count = x.row_count + included_rows = dataframe.row_count + index = Dataframe_Column.from_vector "" (Vector.new included_rows i->i) + + ## Workaround so that the JS String is converted to a Text + https://www.pivotaltracker.com/story/show/184061302 + "" + make_json dataframe [index] all_rows_count + + _ : Database_Table -> + df = x.read max_rows + all_rows_count = x.row_count + + ## Workaround so that the JS String is converted to a Text + https://www.pivotaltracker.com/story/show/184061302 + "" + make_json df [] all_rows_count + + # We display columns as 1-column tables. + _ : Dataframe_Column -> + prepare_visualization x.to_table max_rows + _ : Database_Column -> + prepare_visualization x.to_table max_rows + + # TODO [RW] Should we truncate Vectors? + # We also visualize Vectors and arrays + _ : Vector -> + truncated = x.take (First max_rows) + JS_Object.from_pairs [["json", truncated], ["all_rows_count", x.length]] . to_text + _ : Array -> + prepare_visualization (Vector.from_polyglot_array x) max_rows + + # Anything else will be visualized with the JSON or matrix visualization + _ -> + JS_Object.from_pairs [["json", x]] . to_text ## PRIVATE Creates a JSON representation for the visualizations. @@ -71,11 +73,12 @@ prepare_visualization x max_rows=1000 = Helpers.recover_errors <| case x of only a fragment is displayed. make_json : (Dataframe_Table | Database_Table) -> Vector Dataframe_Column -> Integer -> Text make_json dataframe indices all_rows_count = - columns = dataframe.columns + get_vector c = Warning.set c.to_vector [] + columns = dataframe.columns header = ["header", columns.map .name] - data = ["data", columns.map .to_vector] + data = ["data", columns.map get_vector] all_rows = ["all_rows_count", all_rows_count] - ixes = ["indices", indices.map .to_vector] + ixes = ["indices", indices.map get_vector] ixes_header = ["indices_header", indices.map .name] - pairs = [header, data, all_rows, ixes, ixes_header] + pairs = [header, data, all_rows, ixes, ixes_header] JS_Object.from_pairs pairs . to_text diff --git a/engine/runtime/src/test/java/org/enso/compiler/ParseStdLibTest.java b/engine/runtime/src/test/java/org/enso/compiler/ParseStdLibTest.java index ae2099fc357e..c9429d90d4ee 100644 --- a/engine/runtime/src/test/java/org/enso/compiler/ParseStdLibTest.java +++ b/engine/runtime/src/test/java/org/enso/compiler/ParseStdLibTest.java @@ -160,8 +160,11 @@ public void runBare() throws Throwable { // Files containing type expressions not supported by old parser. "Data/Index_Sub_Range.enso", "Data/Json.enso", + "Data/List.enso", "Data/Pair.enso", + "Data/Range.enso", "Data/Sort_Column_Selector.enso", + "Data/Text/Extensions.enso", "Data/Text/Regex/Regex_Mode.enso", "Data/Value_Type.enso", "Data/Vector.enso", diff --git a/test/Benchmarks/src/Vector/Operations.enso b/test/Benchmarks/src/Vector/Operations.enso index e38d24094a31..4c428c621d55 100644 --- a/test/Benchmarks/src/Vector/Operations.enso +++ b/test/Benchmarks/src/Vector/Operations.enso @@ -28,9 +28,9 @@ bench = Bench.measure (Base.Vector.fill vector_size random_gen.nextLong) "Fill Random (constant)" iter_size num_iterations Bench.measure (random_vec + [1]) "Append Single" iter_size num_iterations Bench.measure (random_vec + random_vec_2) "Append Large" iter_size num_iterations - Bench.measure (random_vec.sum) "Sum" iter_size num_iterations - Bench.measure ((random_vec.drop (First 20)).sum) "Drop First 20 and Sum" iter_size num_iterations - Bench.measure ((random_vec.drop (Last 20)).sum) "Drop Last 20 and Sum" iter_size num_iterations + Bench.measure (random_vec.reduce (+)) "Sum" iter_size num_iterations + Bench.measure ((random_vec.drop (First 20)).reduce (+)) "Drop First 20 and Sum" iter_size num_iterations + Bench.measure ((random_vec.drop (Last 20)).reduce (+)) "Drop Last 20 and Sum" iter_size num_iterations Bench.measure (random_vec.filter (x -> x % 3 == 1)) "Filter" iter_size num_iterations Bench.measure (random_vec.filter_with_index (i-> x-> (i+x) % 3 == 1)) "Filter With Index" iter_size num_iterations diff --git a/test/Benchmarks/src/Vector/Sort.enso b/test/Benchmarks/src/Vector/Sort.enso index 974f3527aef5..f7ff2a3067cc 100644 --- a/test/Benchmarks/src/Vector/Sort.enso +++ b/test/Benchmarks/src/Vector/Sort.enso @@ -60,11 +60,11 @@ bench = comparator = l -> r -> r.compare_to l Bench.measure (sorted_vec.sort) "Already Sorted" iter_size num_iterations - Bench.measure (sorted_vec.sort order=Sort_Direction.Descending) "Sorted in Opposite Order" iter_size num_iterations + Bench.measure (sorted_vec.sort Sort_Direction.Descending) "Sorted in Opposite Order" iter_size num_iterations Bench.measure (partially_sorted_vec.sort) "Sorted Runs Ascending" iter_size num_iterations - Bench.measure (partially_sorted_vec.sort order=Sort_Direction.Descending) "Sorted Runs Descending" iter_size num_iterations + Bench.measure (partially_sorted_vec.sort Sort_Direction.Descending) "Sorted Runs Descending" iter_size num_iterations Bench.measure (random_vec.sort) "Random Elements Ascending" iter_size num_iterations - Bench.measure (random_vec.sort order=Sort_Direction.Descending) "Random Elements Descending" iter_size num_iterations + Bench.measure (random_vec.sort Sort_Direction.Descending) "Random Elements Descending" iter_size num_iterations Bench.measure (random_vec.sort on=projection) "Sorting with a Custom Projection" iter_size num_iterations Bench.measure (random_vec.sort by=comparator) "Sorting with a Custom Comparison" iter_size num_iterations diff --git a/test/Table_Tests/src/Common_Table_Operations/Select_Columns_Spec.enso b/test/Table_Tests/src/Common_Table_Operations/Select_Columns_Spec.enso index daaeb66c10ba..c7cdb672868f 100644 --- a/test/Table_Tests/src/Common_Table_Operations/Select_Columns_Spec.enso +++ b/test/Table_Tests/src/Common_Table_Operations/Select_Columns_Spec.enso @@ -166,7 +166,7 @@ spec setup = expect_column_names ["foo", "bar", "foo_2", "ab.+123", "abcd123"] <| table.remove_columns (By_Column [column1, column2]) Test.specify "should correctly handle regex matching" <| - last_ones = table.columns.tail.map .name + last_ones = table.columns.drop 1 . map .name expect_column_names last_ones <| table.remove_columns (By_Name ["foo"] (Regex_Matcher.Value case_sensitivity=Case_Sensitivity.Sensitive)) first_ones = ["foo", "bar", "Baz", "foo_1", "foo_2"] expect_column_names first_ones <| table.remove_columns (By_Name ["a.*"] (Regex_Matcher.Value case_sensitivity=Case_Sensitivity.Sensitive)) @@ -401,7 +401,7 @@ spec setup = expect_column_names ["Foo_2", "bar", "foo_001", "foo_1", "foo_3", "foo_21", "foo_100"] <| table.sort_columns text_ordering=(Text_Ordering.Default sort_digits_as_numbers=True) Test.specify "should correctly handle various combinations of options" <| - expect_column_names ["foo_100", "foo_21", "foo_3", "Foo_2", "foo_1", "foo_001", "bar"] <| table.sort_columns direction=Sort_Direction.Descending text_ordering=(Text_Ordering.Case_Insensitive sort_digits_as_numbers=True) + expect_column_names ["foo_100", "foo_21", "foo_3", "Foo_2", "foo_1", "foo_001", "bar"] <| table.sort_columns Sort_Direction.Descending text_ordering=(Text_Ordering.Case_Insensitive sort_digits_as_numbers=True) Test.group prefix+"Table.rename_columns" <| table = diff --git a/test/Table_Tests/src/Database/Common_Spec.enso b/test/Table_Tests/src/Database/Common_Spec.enso index 253004107305..f92f4ef6b684 100644 --- a/test/Table_Tests/src/Database/Common_Spec.enso +++ b/test/Table_Tests/src/Database/Common_Spec.enso @@ -168,7 +168,7 @@ spec prefix connection = r_1 = c.sort r_1.to_vector.should_equal [Nothing, Nothing, 2.2, 3.0, 3.0, 7.3] - r_2 = c.sort order=Sort_Direction.Descending + r_2 = c.sort Sort_Direction.Descending r_2.to_vector.should_equal [7.3, 3.0, 3.0, 2.2, Nothing, Nothing] Test.group prefix+"Aggregation" <| diff --git a/test/Table_Tests/src/Formatting/Parse_Values_Spec.enso b/test/Table_Tests/src/Formatting/Parse_Values_Spec.enso index fbe4c10164b6..dbde4d95674e 100644 --- a/test/Table_Tests/src/Formatting/Parse_Values_Spec.enso +++ b/test/Table_Tests/src/Formatting/Parse_Values_Spec.enso @@ -1,7 +1,6 @@ from Standard.Base import all from Standard.Table import Table, Data_Formatter -from Standard.Table.Data.Table import Empty_Error from Standard.Table.Data.Column_Type_Selection import Column_Type_Selection, Auto from Standard.Table.Errors import Invalid_Format, Leading_Zeros, Missing_Input_Columns, Column_Indexes_Out_Of_Range, Duplicate_Type_Selector diff --git a/test/Table_Tests/src/In_Memory/Column_Spec.enso b/test/Table_Tests/src/In_Memory/Column_Spec.enso index 36bf10fa8654..3ca26e5f01a9 100644 --- a/test/Table_Tests/src/In_Memory/Column_Spec.enso +++ b/test/Table_Tests/src/In_Memory/Column_Spec.enso @@ -2,7 +2,6 @@ from Standard.Base import all import Standard.Base.Error.Common.Index_Out_Of_Bounds from Standard.Table import Column -import Standard.Table.Data.Column.Empty_Error import Standard.Table.Data.Storage.Storage import Standard.Examples @@ -59,11 +58,11 @@ spec = Test.group "Columns" <| Test.specify "should be able to get the first element" <| test_column.first . should_equal 1 - empty_column.first.should_fail_with Empty_Error + empty_column.first.should_fail_with Index_Out_Of_Bounds.Error Test.specify "should be able to get the last element" <| test_column.last . should_equal 6 - empty_column.last.should_fail_with Empty_Error + empty_column.last.should_fail_with Index_Out_Of_Bounds.Error Test.specify "should be able to be reversed" <| expected_1 = Column.from_vector "Test" [6, 4, 2, 5, 3, 1] diff --git a/test/Table_Tests/src/In_Memory/Table_Spec.enso b/test/Table_Tests/src/In_Memory/Table_Spec.enso index c538a833145f..bafcd0967f7e 100644 --- a/test/Table_Tests/src/In_Memory/Table_Spec.enso +++ b/test/Table_Tests/src/In_Memory/Table_Spec.enso @@ -7,7 +7,6 @@ import Standard.Base.Error.Incomparable_Values.Incomparable_Values from Standard.Table import Table, Column, Sort_Column, Column_Selector, Sort_Column_Selector, Aggregate_Column import Standard.Table.Main as Table_Module from Standard.Table.Data.Aggregate_Column.Aggregate_Column import all hiding First, Last -from Standard.Table.Data.Table import Empty_Error from Standard.Table.Data.Storage import Storage import Standard.Table.Data.Value_Type.Value_Type from Standard.Table.Errors import Invalid_Output_Column_Names, Duplicate_Output_Column_Names, No_Input_Columns_Selected, Missing_Input_Columns, No_Such_Column, Floating_Point_Grouping, Invalid_Value_Type @@ -438,10 +437,10 @@ spec = r_1 = c.sort r_1.to_vector.should_equal [1,4,7,8,Nothing,Nothing] - r_2 = c.sort order=Sort_Direction.Descending + r_2 = c.sort Sort_Direction.Descending r_2.to_vector.should_equal [8,7,4,1,Nothing,Nothing] - r_3 = c.sort order=Sort_Direction.Descending missing_last=False + r_3 = c.sort Sort_Direction.Descending missing_last=False r_3.to_vector.should_equal [Nothing,Nothing,8,7,4,1] Test.specify 'should respect defined comparison operations for custom types' <| @@ -452,7 +451,7 @@ spec = Test.specify 'should allow passing a custom comparator' <| c = Column.from_vector 'foo' [My.Data 1 2, My.Data 2 5, My.Data 3 4, My.Data 6 3, Nothing, My.Data 1 0] cmp a b = (a.x-a.y).abs . compare_to (b.x-b.y).abs - r = c.sort comparator=cmp + r = c.sort by=cmp r.to_vector.should_equal [My.Data 1 2, My.Data 3 4, My.Data 1 0, My.Data 2 5, My.Data 6 3, Nothing] Test.specify 'should handle Unicode characters correctly' <| @@ -534,11 +533,11 @@ spec = Test.specify "should allow taking/dropping a prefix of rows that satisfy a predicate" <| t1 = Table.new [["X", [1, 2, 3, 4, 5, 5]], ["Y", [9, 8, 7, 2, 10, 5]]] - t2 = t1.take (Index_Sub_Range.While row-> row.to_vector.sum == 10) + t2 = t1.take (Index_Sub_Range.While row-> row.to_vector.compute Statistic.Sum == 10) t2.at "X" . to_vector . should_equal [1, 2, 3] t2.at "Y" . to_vector . should_equal [9, 8, 7] - t3 = t1.drop (Index_Sub_Range.While row-> row.to_vector.sum == 10) + t3 = t1.drop (Index_Sub_Range.While row-> row.to_vector.compute Statistic.Sum == 10) t3.at "X" . to_vector . should_equal [4, 5, 5] t3.at "Y" . to_vector . should_equal [2, 10, 5] diff --git a/test/Tests/src/Data/List_Spec.enso b/test/Tests/src/Data/List_Spec.enso index 00e825394c93..51aabcad15f2 100644 --- a/test/Tests/src/Data/List_Spec.enso +++ b/test/Tests/src/Data/List_Spec.enso @@ -1,8 +1,10 @@ from Standard.Base import all +import Standard.Base.Data.List.Empty_Error +import Standard.Base.Error.Common.Index_Out_Of_Bounds import Standard.Base.Error.Common.No_Such_Method +import Standard.Base.Error.Common.Not_Found import Standard.Base.Error.Common.Unsupported_Argument_Types import Standard.Base.Runtime.State -from Standard.Base.Data.List import Empty_Error from Standard.Test import Test, Test_Suite import Standard.Test.Extensions @@ -15,15 +17,13 @@ spec = Test.group "List" <| Test.specify "should have well defined length when empty" <| List.Nil.length.should_equal 0 Test.specify "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 - Test.specify "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 + l.fold 0 (+) . should_equal 6 + l.fold 1 (*) . should_equal 6 + Test.specify "should allow reducing the list with an arbitrary operation with .reduce" <| + l.reduce (+) . should_equal 6 + l.reduce (*) . should_equal 6 + empty.reduce (+) . should_fail_with Empty_Error + empty.reduce (+) 0 . should_equal 0 Test.specify "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) @@ -38,6 +38,49 @@ spec = Test.group "List" <| l.contains 4 . should_be_false l.contains 3 . should_be_true empty.contains 10 . should_be_false + Test.specify "should allow finding an element in the list with `.find`" <| + l.find (==2) . should_equal 2 + l.find (==3) . should_equal 3 + l.find (==4) . should_fail_with Not_Found + l.find (==2) start=1 . should_equal 2 + l.find (==2) start=2 . should_fail_with Not_Found + l.find (==2) start=3 . should_fail_with Not_Found + l.find (==2) start=-1 . should_fail_with Not_Found + l.find (==2) start=-2 . should_equal 2 + l.find (==2) start=4 . should_fail_with Index_Out_Of_Bounds.Error + l.find (==2) start=4 . catch . should_equal (Index_Out_Of_Bounds.Error 4 4) + empty.find (==1) . should_fail_with Not_Found + empty.find (==1) if_missing=Nothing . should_equal Nothing + Test.specify "should allow finding the index of an element in the list with `.index_of`" <| + l.index_of (==2) . should_equal 1 + l.index_of 3 . should_equal 2 + l.index_of (==4) . should_equal Nothing + empty.index_of (==1) . should_equal Nothing + l.index_of (==2) start=1 . should_equal 1 + l.index_of 2 start=2 . should_equal Nothing + l.index_of 2 start=3 . should_equal Nothing + l.index_of 2 start=-1 . should_equal Nothing + l.index_of (==2) start=-2 . should_equal 1 + l.index_of 2 start=4 . should_fail_with Index_Out_Of_Bounds.Error + l.index_of 2 start=4 . catch . should_equal (Index_Out_Of_Bounds.Error 4 4) + l.index_of 2 start=-3 . should_equal 1 + l.index_of 2 start=-4 . should_fail_with Index_Out_Of_Bounds.Error + l.index_of 2 start=-4 . should_fail_with Index_Out_Of_Bounds.Error + Test.specify "should allow finding the last index of an element in the list with `.last_index_of`" <| + ll = List.Cons 1 <| List.Cons 2 <| List.Cons 3 <| List.Cons 1 <| List.Cons 2 <| List.Cons 3 <| List.Nil + ll.last_index_of (==2) . should_equal 4 + ll.last_index_of 3 . should_equal 5 + ll.last_index_of (==4) . should_equal Nothing + ll.last_index_of (==2) start=3 . should_equal 1 + empty.last_index_of (==1) . should_equal Nothing + ll.last_index_of 3 start=1 . should_equal Nothing + ll.last_index_of 3 start=5 . should_equal 5 + ll.last_index_of 3 start=6 . should_fail_with Index_Out_Of_Bounds.Error + ll.last_index_of 3 start=6 . catch . should_equal (Index_Out_Of_Bounds.Error 6 6) + ll.last_index_of 2 start=-3 . should_equal 1 + ll.last_index_of 2 start=-6 . should_equal Nothing + ll.last_index_of 3 start=-7 . should_fail_with Index_Out_Of_Bounds.Error + ll.last_index_of (==2) start=-2 . should_equal 4 Test.specify "should allow checking if the list is empty with `.is_empty`" <| l.is_empty . should_be_false empty.is_empty . should_be_true @@ -93,7 +136,7 @@ spec = Test.group "List" <| bools.filter Filter_Condition.Is_True . should_equal [True, True].to_list bools.filter Filter_Condition.Is_False . should_equal [False].to_list Test.specify "should allow mapping a function over its elements with .map" <| - l.map +1 . head . should_equal 2 + l.map +1 . first . should_equal 2 Test.specify "should allow executing an action for each element with .each" <| sum = State.run Number 0 <| l.each el-> @@ -102,34 +145,60 @@ spec = Test.group "List" <| State.get Number sum.should_equal 6 Test.specify "should allow reversing with .reverse" <| - l.reverse.head.should_equal 3 + l.reverse.first.should_equal 3 Test.specify "should allow dropping elements from the left with `.drop`" <| l.drop_start 1 . should_equal (List.Cons 2 (List.Cons 3 List.Nil)) empty.drop_start 1 . should_equal List.Nil Test.specify "should allow taking elements from the left with `.take_start`" <| l.take_start 2 . should_equal (List.Cons 1 (List.Cons 2 List.Nil)) empty.take_start 2 . should_equal List.Nil - Test.specify "should allow getting the head of the list with `.head`" <| - l.head . should_equal 1 - empty.head.should_fail_with Empty_Error Test.specify "should allow getting the tail of the list with `.tail`" <| l.tail . should_equal (List.Cons 2 (List.Cons 3 List.Nil)) - empty.tail.should_fail_with Empty_Error + empty.tail.should_fail_with Index_Out_Of_Bounds.Error Test.specify "single element list.init yields Nil" <| (List.Cons 1 List.Nil).init . should_equal List.Nil Test.specify "two element list.init yields one element" <| (List.Cons 1 (List.Cons 2 List.Nil)).init . should_equal (List.Cons 1 List.Nil) Test.specify "should allow getting the init of the list with `.init`" <| l.init . should_equal (List.Cons 1 (List.Cons 2 List.Nil)) - empty.init.should_fail_with Empty_Error + empty.init.should_fail_with Index_Out_Of_Bounds.Error Test.specify "should allow getting the last element of the list with `.last`" <| l.last . should_equal 3 - empty.last.should_fail_with Empty_Error + empty.last.should_fail_with Index_Out_Of_Bounds.Error Test.specify "should allow getting the head of the list with `.first`" <| l.first . should_equal 1 - empty.first.should_fail_with Empty_Error - Test.specify "should allow getting the tail of the list with `.rest`" <| - l.rest . should_equal (List.Cons 2 (List.Cons 3 List.Nil)) - empty.rest.should_fail_with Empty_Error + empty.first.should_fail_with Index_Out_Of_Bounds.Error + empty.first.catch.should_equal (Index_Out_Of_Bounds.Error 0 0) + Test.specify "should allow getting the second item of the list with `.second`" <| + l.second . should_equal 2 + empty.second.should_fail_with Index_Out_Of_Bounds.Error + empty.second.catch.should_equal (Index_Out_Of_Bounds.Error 1 0) + (List.Cons 1 List.Nil).second.should_fail_with Index_Out_Of_Bounds.Error + (List.Cons 1 List.Nil).second.catch.should_equal (Index_Out_Of_Bounds.Error 1 1) + Test.specify "should allow getting the last element of the list with `.last`" <| + l.last . should_equal 3 + empty.last.should_fail_with Index_Out_Of_Bounds.Error + empty.last.catch.should_equal (Index_Out_Of_Bounds.Error -1 0) + Test.specify "should allow getting the items of the list with `.at`" <| + l.at 0 . should_equal 1 + l.at 1 . should_equal 2 + l.at 2 . should_equal 3 + l.at -3 . should_equal 1 + l.at -2 . should_equal 2 + l.at -1 . should_equal 3 + empty.at 0 . should_fail_with Index_Out_Of_Bounds.Error + l.at 3 . should_fail_with Index_Out_Of_Bounds.Error + l.at -4 . should_fail_with Index_Out_Of_Bounds.Error + Test.specify "should allow getting the items of the list with `.get`" <| + l.get 0 . should_equal 1 + l.get 1 . should_equal 2 + l.get 2 . should_equal 3 + l.get -3 . should_equal 1 + l.get -2 . should_equal 2 + l.get -1 . should_equal 3 + empty.get 0 . should_equal Nothing + empty.get 0 "A" . should_equal "A" + l.get 3 . should_equal Nothing + l.get -4 . should_equal Nothing main = Test_Suite.run_main spec diff --git a/test/Tests/src/Data/Map_Spec.enso b/test/Tests/src/Data/Map_Spec.enso index 7588feb2a70b..433a5e10492a 100644 --- a/test/Tests/src/Data/Map_Spec.enso +++ b/test/Tests/src/Data/Map_Spec.enso @@ -51,6 +51,10 @@ spec = Test.group "Maps" <| m.get 2 0 . should_equal 3 m.get 1 10 . should_equal 10 m.get 2 (Panic.throw "missing") . should_equal 3 + Test.specify "should support contains_key" <| + m = Map.empty . insert 2 3 + m.contains_key 2 . should_be_true + m.contains_key 1 . should_be_false Test.specify "should allow transforming the map" <| m = Map.empty . insert 1 2 . insert 2 4 expected = Map.empty . insert "1" 4 . insert "2" 8 diff --git a/test/Tests/src/Data/Pair_Spec.enso b/test/Tests/src/Data/Pair_Spec.enso index e123a485efaf..b6b5da6ed764 100644 --- a/test/Tests/src/Data/Pair_Spec.enso +++ b/test/Tests/src/Data/Pair_Spec.enso @@ -1,23 +1,113 @@ from Standard.Base import all import Standard.Base.Error.Common.Index_Out_Of_Bounds +import Standard.Base.Error.Common.Not_Found from Standard.Test import Test, Test_Suite import Standard.Test.Extensions -spec = Test.group "Pair" <| - Test.specify "should be created by new" <| - Pair.new 1 2 . should_equal (Pair.Value 1 2) - +type_spec name ctor = Test.group name <| Test.specify "should allow mapping" <| - Pair.new 1 2 . map x->x+1 . should_equal (Pair.Value 2 3) - - Test.specify "should act as a length 2 Vector" <| - Pair.new "A" "B" . length . should_equal 2 - Pair.new "A" "B" . at 0 . should_equal "A" - Pair.new "A" "B" . at -2 . should_equal "A" - Pair.new "A" "B" . at 1 . should_equal "B" - Pair.new "A" "B" . at -1 . should_equal "B" - Pair.new "A" "B" . at 2 . should_fail_with Index_Out_Of_Bounds.Error - Pair.new "A" "B" . to_vector . should_equal ["A", "B"] + ctor 1 2 . map x->x+1 . should_equal (ctor 2 3) + + Test.specify "should have length 2" <| + ctor "A" "B" . length . should_equal 2 + + Test.specify "should allow reversing" <| + ctor 1 2 . reverse . should_equal (ctor 2 1) + + Test.specify "should have allow getting by index" <| + ctor "A" "B" . get 0 . should_equal "A" + ctor "A" "B" . get -2 . should_equal "A" + ctor "A" "B" . get 1 . should_equal "B" + ctor "A" "B" . get -1 . should_equal "B" + ctor "A" "B" . get 2 . should_equal Nothing + ctor "A" "B" . get -3 "C" . should_equal "C" + ctor "A" "B" . at 0 . should_equal "A" + ctor "A" "B" . at -2 . should_equal "A" + ctor "A" "B" . at 1 . should_equal "B" + ctor "A" "B" . at -1 . should_equal "B" + ctor "A" "B" . at 2 . should_fail_with Index_Out_Of_Bounds.Error + + Test.specify "should have allow getting by first, second and last" <| + ctor "A" "B" . first . should_equal "A" + ctor "A" "B" . second . should_equal "B" + ctor "A" "B" . last . should_equal "B" + + Test.specify "should be convertable to a vector" <| + ctor "A" "B" . to_vector . should_equal ["A", "B"] + + Test.specify "should allow checking all, any and contains" <| + ctor 1 3 . any (>0) . should_equal True + ctor 1 3 . any (>2) . should_equal True + ctor 1 3 . any (>3) . should_equal False + ctor 1 3 . all (>0) . should_equal True + ctor 1 3 . all (>2) . should_equal False + ctor 1 3 . all (>3) . should_equal False + ctor 1 3 . contains 1 . should_equal True + ctor 1 3 . contains 2 . should_equal False + ctor 1 3 . contains 3 . should_equal True + + Test.specify "should allow finding an item" <| + ctor 1 3 . find (>0) . should_equal 1 + ctor 1 3 . find (>2) . should_equal 3 + ctor 1 3 . find (>3) . should_fail_with Not_Found + ctor 1 3 . find (>0) start=1 . should_equal 3 + ctor 1 3 . find (>0) start=2 . should_fail_with Not_Found + ctor 1 3 . find (>0) start=-1 . should_equal 3 + ctor 1 3 . find (>0) start=4 . should_fail_with Index_Out_Of_Bounds.Error + ctor 1 3 . find (>0) start=-22 . should_fail_with Index_Out_Of_Bounds.Error + ctor 10 30 . find (>0) start=3 . should_fail_with Index_Out_Of_Bounds.Error + ctor 10 30 . find (>0) start=3 . catch . should_equal (Index_Out_Of_Bounds.Error 3 3) + ctor 1 3 . find (>3) if_missing=Nothing . should_equal Nothing + + Test.specify "should allow finding the index of an item" <| + ctor 10 30 . index_of 10 . should_equal 0 + ctor 10 10 . index_of 10 . should_equal 0 + ctor 10 30 . index_of 30 . should_equal 1 + ctor 10 30 . index_of 20 . should_equal Nothing + ctor 10 30 . index_of (>20) . should_equal 1 + ctor 10 30 . index_of (>0) start=1 . should_equal 1 + ctor 10 30 . index_of (>0) start=2 . should_equal Nothing + ctor 10 30 . index_of (>0) start=-1 . should_equal 1 + ctor 10 30 . index_of (>0) start=3 . should_fail_with Index_Out_Of_Bounds.Error + ctor 10 30 . index_of (>0) start=3 . catch . should_equal (Index_Out_Of_Bounds.Error 3 3) + ctor 10 30 . index_of (>0) start=4 . should_fail_with Index_Out_Of_Bounds.Error + ctor 10 30 . index_of (>0) start=-22 . should_fail_with Index_Out_Of_Bounds.Error + + Test.specify "should allow finding the last index of an item" <| + ctor 10 30 . last_index_of 10 . should_equal 0 + ctor 10 10 . last_index_of 10 . should_equal 1 + ctor 10 30 . last_index_of 30 . should_equal 1 + ctor 10 30 . last_index_of 20 . should_equal Nothing + ctor 10 30 . last_index_of (>20) . should_equal 1 + ctor 10 30 . last_index_of (>0) start=1 . should_equal 1 + ctor 10 30 . last_index_of (>0) start=-1 . should_equal 1 + ctor 10 30 . last_index_of (>0) start=2 . should_fail_with Index_Out_Of_Bounds.Error + ctor 10 30 . last_index_of (>0) start=2 . catch . should_equal (Index_Out_Of_Bounds.Error 2 2) + ctor 10 30 . last_index_of (>0) start=4 . should_fail_with Index_Out_Of_Bounds.Error + ctor 10 30 . last_index_of (>0) start=-22 . should_fail_with Index_Out_Of_Bounds.Error + + Test.specify "should allow folding an operator over its elements" <| + ctor 10 20 . fold 0 (+) . should_equal 30 + ctor "A" "B" . fold "" (+) . should_equal "AB" + + Test.specify "should allow reducing an operator over its elements" <| + ctor 10 20 . reduce (*) . should_equal 200 + ctor "Hello" "World" . reduce (a->b-> a+" "+b) . should_equal "Hello World" + + Test.specify "should allow applying a function to each element" <| + vec_mut = Vector.new_builder + ctor 10 20 . each vec_mut.append + vec_mut.to_vector . should_equal [10, 20] + +spec = + Test.group "Pair " <| + Test.specify "should be created by new" <| + Pair.new 1 2 . should_equal (Pair.Value 1 2) + + type_spec "Pair - from Pair.new" Pair.new + type_spec "Pair - from Pair.Value" Pair.Value + type_spec "Pair - from 2-Item Vector" a->b->[a,b] + type_spec "Pair - from 2-Item List" a->b->(List.Cons a (List.Cons b List.Nil)) main = Test_Suite.run_main spec diff --git a/test/Tests/src/Data/Range_Spec.enso b/test/Tests/src/Data/Range_Spec.enso index 1f0da29b94c2..b7f4ca403f90 100644 --- a/test/Tests/src/Data/Range_Spec.enso +++ b/test/Tests/src/Data/Range_Spec.enso @@ -1,4 +1,6 @@ from Standard.Base import all +import Standard.Base.Data.Range.Empty_Error +import Standard.Base.Error.Common.Index_Out_Of_Bounds import Standard.Base.Error.Common.No_Such_Method import Standard.Base.Error.Common.Unsupported_Argument_Types import Standard.Base.Error.Illegal_Argument.Illegal_Argument @@ -70,6 +72,54 @@ spec = Test.group "Range" <| 0.up_to 1 . not_empty . should_be_true 0.up_to 5 . not_empty . should_be_true 5.down_to 0 . not_empty . should_be_true + Test.specify "should allow getting by index using at" <| + 0.up_to 0 . at 0 . should_fail_with Index_Out_Of_Bounds.Error + 0.up_to 100 . at 0 . should_equal 0 + 0.up_to 100 . at 5 . should_equal 5 + 0.up_to 100 . at -1 . should_equal 99 + 0.up_to 100 . at -100 . should_equal 0 + 0.up_to 100 . at 100 . should_fail_with Index_Out_Of_Bounds.Error + 0.up_to 100 . at 100 . catch . should_equal (Index_Out_Of_Bounds.Error 100 100) + 0.up_to 100 . at -123 . should_fail_with Index_Out_Of_Bounds.Error + 1.up_to 100 . with_step 5 . at 0 . should_equal 1 + 1.up_to 100 . with_step 5 . at 3 . should_equal 16 + 1.up_to 100 . with_step 5 . at -1 . should_equal 96 + 1.up_to 100 . with_step 5 . at -3 . should_equal 86 + Test.specify "should allow getting by index using get" <| + 0.up_to 0 . get 0 . should_equal Nothing + 0.up_to 100 . get 0 . should_equal 0 + 0.up_to 100 . get 5 . should_equal 5 + 0.up_to 100 . get -1 . should_equal 99 + 0.up_to 100 . get -100 . should_equal 0 + 0.up_to 100 . get 100 . should_equal Nothing + 0.up_to 100 . get -123 . should_equal Nothing + 1.up_to 100 . with_step 5 . get 0 . should_equal 1 + 1.up_to 100 . with_step 5 . get 3 . should_equal 16 + 1.up_to 100 . with_step 5 . get -1 . should_equal 96 + 1.up_to 100 . with_step 5 . get -3 . should_equal 86 + Test.specify "should allow getting first" <| + 0.up_to 0 . first . should_fail_with Index_Out_Of_Bounds.Error + 0.up_to 0 . first . catch . should_equal (Index_Out_Of_Bounds.Error 0 0) + 3.up_to 100 . first . should_equal 3 + 0.down_to 0 . first . should_fail_with Index_Out_Of_Bounds.Error + 0.down_to -3 . first . should_equal 0 + Test.specify "should allow getting second" <| + 0.up_to 0 . second . should_fail_with Index_Out_Of_Bounds.Error + 0.up_to 0 . second . catch . should_equal (Index_Out_Of_Bounds.Error 1 0) + 3.up_to 100 . second . should_equal 4 + 3.up_to 100 . with_step 10 . second . should_equal 13 + 3.up_to 10 . with_step 10 . second . should_fail_with Index_Out_Of_Bounds.Error + 0.down_to 0 . second . should_fail_with Index_Out_Of_Bounds.Error + 0.down_to -3 . second . should_equal -1 + 0.down_to -3 . with_step 2 . second . should_equal -2 + 0.down_to -3 . with_step 4 . second . should_fail_with Index_Out_Of_Bounds.Error + Test.specify "should allow getting last" <| + 0.up_to 0 . last . should_fail_with Index_Out_Of_Bounds.Error + 0.up_to 0 . last . catch . should_equal (Index_Out_Of_Bounds.Error 0 0) + 3.up_to 100 . last . should_equal 99 + 3.up_to 100 . with_step 25 . last . should_equal 78 + 0.down_to 0 . last . should_fail_with Index_Out_Of_Bounds.Error + 0.down_to -3 . last . should_equal -2 Test.specify "should be able to be mapped over to make a Vector" <| empty = 0.up_to 0 empty.map *2 . should_equal [] @@ -129,20 +179,62 @@ spec = Test.group "Range" <| Test.specify "should be able to perform a running fold" <| 1.up_to 6 . running_fold 0 (+) . should_equal [1, 3, 6, 10, 15] 1.up_to 1 . running_fold 123 (+) . should_equal [] + Test.specify "should be able to be reduced" <| + 1.up_to 6 . reduce (+) . should_equal 15 + 1.up_to 6 . with_step 2 . reduce (+) . should_equal 9 + 1.up_to 1 . reduce (+) . should_fail_with Empty_Error + 1.up_to 1 . reduce (+) 0 . should_equal 0 Test.specify "should check all" <| 1.up_to 10 . all (> 0) . should_be_true 1.up_to 10 . all (< 0) . should_be_false - Test.specify "should check exists" <| - 1.up_to 10 . exists (> 5) . should_be_true - 1.up_to 10 . exists (> 10) . should_be_false Test.specify "should check any" <| 1.up_to 10 . any (> 5) . should_be_true 1.up_to 10 . any (> 10) . should_be_false Test.specify "should find elements" <| 1.up_to 10 . find (> 5) . should_equal 6 1.up_to 10 . find (> 10) . should_be_a Nothing + 1.up_to 10 . find (v-> v%4 == 0) start=6 . should_equal 8 + 1.up_to 10 . find (< 5) start=6 . should_be_a Nothing + 1.up_to 10 . find (< 5) start=10 . should_fail_with Index_Out_Of_Bounds.Error + 1.up_to 10 . find (< 5) start=10 . catch . should_equal (Index_Out_Of_Bounds.Error 10 10) + Test.specify "should find index of elements" <| + 1.up_to 10 . index_of (> 5) . should_equal 5 + 1.up_to 10 . index_of 7 . should_equal 6 + 1.up_to 10 . with_step 2 . index_of (> 4) . should_equal 2 + 1.up_to 10 . with_step 2 . index_of 7 . should_equal 3 + 1.up_to 10 . index_of (> 10) . should_be_a Nothing + 1.up_to 10 . index_of (v-> v%4 == 0) start=6 . should_equal 7 + 1.up_to 10 . index_of 2.5 . should_fail_with Illegal_Argument.Error + 0.up_to 0 . index_of 1 . should_be_a Nothing + 1.up_to 10 . index_of (< 5) start=3 . should_equal 3 + 1.up_to 10 . index_of (< 5) start=6 . should_be_a Nothing + 1.up_to 10 . index_of (< 5) start=9 . should_be_a Nothing + 1.up_to 10 . index_of (< 5) start=10 . should_fail_with Index_Out_Of_Bounds.Error + 1.up_to 10 . index_of (< 5) start=10 . catch . should_equal (Index_Out_Of_Bounds.Error 10 10) + 1.up_to 10 . index_of (< 5) start=-1 . should_equal Nothing + 1.up_to 10 . index_of (< 5) start=-9 . should_equal 0 + Test.specify "should find last index of elements" <| + 1.up_to 10 . last_index_of (> 5) . should_equal 8 + 1.up_to 10 . last_index_of 7 . should_equal 6 + 1.up_to 10 . with_step 2 . last_index_of (> 4) . should_equal 4 + 1.up_to 10 . with_step 2 . last_index_of 7 . should_equal 3 + 1.up_to 10 . last_index_of (> 10) . should_be_a Nothing + 1.up_to 10 . last_index_of (v-> v%4 == 0) start=6 . should_equal 3 + 1.up_to 10 . last_index_of 2.5 . should_fail_with Illegal_Argument.Error + 0.up_to 0 . last_index_of 1 . should_be_a Nothing + 1.up_to 10 . last_index_of (< 5) start=2 . should_equal 2 + 1.up_to 10 . last_index_of (< 5) start=6 . should_equal 3 + 1.up_to 10 . last_index_of (< 5) start=-1 . should_equal 3 + 1.up_to 10 . last_index_of (< 5) start=-7 . should_equal 2 + 1.up_to 10 . last_index_of (< 5) start=9 . should_fail_with Index_Out_Of_Bounds.Error + 1.up_to 10 . last_index_of (< 5) start=10 . catch . should_equal (Index_Out_Of_Bounds.Error 10 9) + 1.up_to 10 . last_index_of (< 5) start=-10 . should_fail_with Index_Out_Of_Bounds.Error Test.specify "should allow conversion to vector" <| 1.up_to 6 . to_vector . should_equal [1, 2, 3, 4, 5] + Test.specify "should allow reversing" <| + 1.up_to 6 . reverse . should_equal (5.down_to 0) + 5.down_to 0 . reverse . should_equal (1.up_to 6) + 1.up_to 6 . with_step 2 . reverse . should_equal (5.down_to -1 . with_step 2) Test.specify "should allow checking if a value is in the range" <| 0.up_to 10 . contains 5 . should_be_true @@ -381,6 +473,11 @@ spec = Test.group "Range" <| 0.up_to 0 . with_step 0 . should_fail_with Illegal_State.Error invalid_range = Range.Between 0 0 0 invalid_range . length . should_fail_with Illegal_State.Error + invalid_range . first . should_fail_with Illegal_State.Error + invalid_range . second . should_fail_with Illegal_State.Error + invalid_range . last . should_fail_with Illegal_State.Error + invalid_range . at 0 . should_fail_with Illegal_State.Error + invalid_range . get 0 . should_fail_with Illegal_State.Error invalid_range . is_empty . should_fail_with Illegal_State.Error invalid_range . not_empty . should_fail_with Illegal_State.Error invalid_range . each x->x . should_fail_with Illegal_State.Error diff --git a/test/Tests/src/Data/Text_Spec.enso b/test/Tests/src/Data/Text_Spec.enso index aea9fa44484f..4c771778ecad 100644 --- a/test/Tests/src/Data/Text_Spec.enso +++ b/test/Tests/src/Data/Text_Spec.enso @@ -156,6 +156,13 @@ spec = str.at 1 . should_equal facepalm str.at 2 . should_equal accent_1 str.at 3 . should_equal accent_2 + str.get 0 . should_equal kshi + str.get 1 . should_equal facepalm + str.get 2 . should_equal accent_1 + str.get 3 . should_equal accent_2 + str.first . should_equal kshi + str.second . should_equal facepalm + str.last . should_equal accent_2 Test.specify "should allow access by negative index to a grapheme cluster" <| str = kshi + facepalm + accent_1 + accent_2 @@ -163,6 +170,10 @@ spec = str.at -3 . should_equal facepalm str.at -2 . should_equal accent_1 str.at -1 . should_equal accent_2 + str.get -4 . should_equal kshi + str.get -3 . should_equal facepalm + str.get -2 . should_equal accent_1 + str.get -1 . should_equal accent_2 Test.specify "should return a dataflow error when accessing characters out of bounds" <| str = kshi + facepalm + accent_1 + accent_2 @@ -170,6 +181,12 @@ spec = str.at -5 . catch . should_equal (Index_Out_Of_Bounds.Error -5 4) str.at 4 . should_fail_with Index_Out_Of_Bounds.Error str.at 4 . catch . should_equal (Index_Out_Of_Bounds.Error 4 4) + str.get -5 . should_equal Nothing + str.get 4 . should_equal Nothing + str.get -5 "?" . should_equal "?" + "".first.should_fail_with Index_Out_Of_Bounds.Error + "".second.should_fail_with Index_Out_Of_Bounds.Error + "".last.should_fail_with Index_Out_Of_Bounds.Error Test.specify "should be able to split the text into words" <| "I have not one, but two cats.".words . should_equal ['I', 'have', 'not', 'one', ',', 'but', 'two', 'cats', '.'] @@ -1124,9 +1141,9 @@ spec = Test.specify "locate should work as shown in examples" <| example_1 = - "Hello World!".locate "J" == Nothing - "Hello World!".locate "o" == Span.Value (4.up_to 5) "Hello World!" - "Hello World!".locate "o" mode=Matching_Mode.Last == Span.Value (4.up_to 5) "Hello World!" + "Hello World!".locate "J" . should_equal Nothing + "Hello World!".locate "o" . should_equal (Span.Value (4.up_to 5) "Hello World!") + "Hello World!".locate "o" mode=Matching_Mode.Last . should_equal (Span.Value (7.up_to 8) "Hello World!") example_2 = term = "straße" @@ -1175,7 +1192,7 @@ spec = example_5 example_6 - Test.specify "should allow to find locate occurrences within a text" <| + Test.specify "should allow to locate occurrences within a text" <| "Hello World!".locate_all "J" . should_equal [] "Hello World!".locate_all "o" . map .start . should_equal [4, 7] @@ -1188,11 +1205,30 @@ spec = "".locate "" . should_equal (Span.Value (0.up_to 0) "") "".locate "" mode=Matching_Mode.Last . should_equal (Span.Value (0.up_to 0) "") "".locate_all "" . should_equal [Span.Value (0.up_to 0) ""] + abc = 'A\u{301}ßC' abc.locate "" . should_equal (Span.Value (0.up_to 0) abc) abc.locate "" mode=Matching_Mode.Last . should_equal (Span.Value (3.up_to 3) abc) abc.locate_all "" . should_equal [Span.Value (0.up_to 0) abc, Span.Value (1.up_to 1) abc, Span.Value (2.up_to 2) abc, Span.Value (3.up_to 3) abc] + Test.specify "should allow to get indexes of values within a text" <| + "Hello World!".index_of "o" . should_equal 4 + "Hello World!".index_of "o" start=5 . should_equal 7 + "Hello World!".index_of "o" start=-5 . should_equal 7 + "Hello World!".index_of "o" start=12 . should_equal Nothing + "Hello World!".index_of "o" start=13 . should_fail_with Index_Out_Of_Bounds.Error + "Hello World!".index_of "o" start=13 . catch . should_equal (Index_Out_Of_Bounds.Error 13 13) + + "Hello World!".last_index_of "o" . should_equal 7 + "Hello World!".last_index_of "o" start=6 . should_equal 4 + "Hello World!".last_index_of "o" start=12 . should_fail_with Index_Out_Of_Bounds.Error + "Hello World!".last_index_of "o" start=12 . catch . should_equal (Index_Out_Of_Bounds.Error 12 12) + + abc = 'A\u{301}ßC' + abc.index_of "" . should_equal 0 + abc.index_of "" start=3 . should_equal 3 + abc.last_index_of "" . should_equal 3 + Test.specify "should allow case-insensitive matching in locate" <| hello = "Hello WORLD!" case_insensitive = Text_Matcher.Case_Insensitive diff --git a/test/Tests/src/Data/Time/Date_Spec.enso b/test/Tests/src/Data/Time/Date_Spec.enso index 7a32619289b3..096c9cc7a24f 100644 --- a/test/Tests/src/Data/Time/Date_Spec.enso +++ b/test/Tests/src/Data/Time/Date_Spec.enso @@ -146,7 +146,7 @@ spec_with name create_new_date parse_date = is_time_error v = case v of _ : Time_Error -> True _ -> False - expect_warning value = (Warning.get_all value . map .value . exists is_time_error) . should_be_true + expect_warning value = (Warning.get_all value . map .value . any is_time_error) . should_be_true dates_before_epoch = [(create_new_date 100), (create_new_date 500 6 3)] dates_before_epoch.each date-> expect_warning date.week_of_year diff --git a/test/Tests/src/Data/Vector_Spec.enso b/test/Tests/src/Data/Vector_Spec.enso index afd5fe935941..65693d54bde0 100644 --- a/test/Tests/src/Data/Vector_Spec.enso +++ b/test/Tests/src/Data/Vector_Spec.enso @@ -2,6 +2,7 @@ from Standard.Base import all import Standard.Base.Data.Vector.Empty_Error import Standard.Base.Error.Common.Index_Out_Of_Bounds import Standard.Base.Error.Common.No_Such_Method +import Standard.Base.Error.Common.Not_Found import Standard.Base.Error.Common.Type_Error import Standard.Base.Error.Common.Unsupported_Argument_Types import Standard.Base.Error.Illegal_Argument.Illegal_Argument @@ -64,7 +65,6 @@ spec = Test.group "Vectors" <| const = Vector.new 4 _->next const.should_equal [0, 1, 2, 3] - Test.specify "should allow vector creation with a constant constructor" <| Vector.fill 100 1 . fold (0) (+) . should_equal 100 @@ -131,16 +131,7 @@ spec = Test.group "Vectors" <| Test.specify "should allow to reduce elements if it is non-empty" <| [1,2,3].reduce (+) . should_equal 6 [].reduce (+) . should_fail_with Empty_Error - - Test.specify "should allow summing elements if they define +" <| - [1,2,3].sum . should_equal 6 - [].sum . should_fail_with Empty_Error - [T.Value 1 2, T.Value 3 4].sum . should_fail_with No_Such_Method.Error - - Test.specify "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 + [].reduce (+) 0 . should_equal 0 Test.specify "should check any" <| vec = [1, 2, 3, 4, 5] @@ -343,6 +334,45 @@ spec = Test.group "Vectors" <| Test.specify "should define concatenation" <| concat = [1, 2, 3] + [4, 5, 6] concat.should_equal [1, 2, 3, 4, 5, 6] + [1, 2, 3]+1 . should_fail_with Type_Error.Error + + Test.specify "should allow finding a value" <| + input = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + input.find (x -> x == 5) . should_equal 5 + input.find (x -> x%3 == 2) . should_equal 2 + input.find (x -> x%3 == 3) . should_fail_with Not_Found + input.find (x -> x%3 == 2) start=3 . should_equal 5 + input.find (x -> x%3 == 2) start=-3 . should_equal 8 + input.find (x -> x%3 == 2) start=10 . should_fail_with Not_Found + input.find (x -> x%3 == 2) start=11 . should_fail_with Index_Out_Of_Bounds.Error + input.find (x -> x%3 == 2) start=11 . catch . should_equal (Index_Out_Of_Bounds.Error 11 11) + input.find (x -> x%3 == 2) start=100 . should_fail_with Index_Out_Of_Bounds.Error + input.find (x -> x%3 == 2) start=-100 . should_fail_with Index_Out_Of_Bounds.Error + input.find (x -> x%3 == 3) if_missing=Nothing . should_equal Nothing + + Test.specify "should allow finding the index of a value" <| + input = [1, 2, 3, 4, 1, 2, 3, 1, 2, 1] + input.index_of 4 . should_equal 3 + input.index_of (>3) . should_equal 3 + input.index_of 5 . should_equal Nothing + [].index_of 5 . should_equal Nothing + input.index_of 2 start=3 . should_equal 5 + input.index_of 2 start=-2 . should_equal 8 + input.index_of 2 start=10 . should_equal Nothing + input.index_of 2 start=11 . should_fail_with Index_Out_Of_Bounds.Error + input.index_of 2 start=11 . catch . should_equal (Index_Out_Of_Bounds.Error 11 11) + input.index_of 2 start=-11 . should_fail_with Index_Out_Of_Bounds.Error + + Test.specify "should allow finding the last index of a value" <| + input = [1, 2, 3, 4, 1, 2, 3, 1, 2, 1] + input.last_index_of 2 . should_equal 8 + input.last_index_of 5 . should_equal Nothing + [].last_index_of 5 . should_equal Nothing + input.last_index_of 2 start=4 . should_equal 1 + input.last_index_of 2 start=-1 . should_equal 8 + input.last_index_of 2 start=10 . should_fail_with Index_Out_Of_Bounds.Error + input.last_index_of 2 start=10 . catch . should_equal (Index_Out_Of_Bounds.Error 10 10) + input.last_index_of 2 start=-11 . should_fail_with Index_Out_Of_Bounds.Error Test.specify "should be convertible to a list" <| [].to_list . should_equal List.Nil @@ -479,37 +509,13 @@ spec = Test.group "Vectors" <| ["a", "a", "a"].drop (Sample 1) . should_equal ["a", "a"] ["a", "a", "a"].drop (Sample 100) . should_equal [] - Test.specify "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_fail_with Empty_Error - - Test.specify "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_fail_with Empty_Error - - Test.specify "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_fail_with Empty_Error - Test.specify "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_fail_with Empty_Error + empty_vec.last . should_fail_with Index_Out_Of_Bounds Test.specify "should allow getting the first element" <| non_empty_vec = [1, 2, 3, 4, 5] @@ -517,15 +523,15 @@ spec = Test.group "Vectors" <| empty_vec = [] non_empty_vec.first . should_equal 1 singleton_vec.first . should_equal 1 - empty_vec.first . should_fail_with Empty_Error + empty_vec.first . should_fail_with Index_Out_Of_Bounds - Test.specify "should allow getting the rest of the vector" <| + Test.specify "should allow getting the second element" <| 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_fail_with Empty_Error + non_empty_vec.second . should_equal 2 + singleton_vec.second . should_fail_with Index_Out_Of_Bounds + empty_vec.second . should_fail_with Index_Out_Of_Bounds Test.specify "should be able to be sorted" <| empty_vec = [] @@ -579,12 +585,12 @@ spec = Test.group "Vectors" <| Test.specify "should be able to sort in descending order" <| small_vec = [2, 7, -3, 383, -392, 28, -90] small_expected = [383, 28, 7, 2, -3, -90, -392] - small_vec.sort order=Sort_Direction.Descending . should_equal small_expected + small_vec.sort Sort_Direction.Descending . should_equal small_expected Test.specify "should be stable in descending order" <| small_vec = [T.Value 1 8, T.Value 1 3, T.Value -20 0, T.Value -1 1, T.Value -1 10, T.Value 4 0] small_expected = [T.Value 4 0, T.Value 1 3, T.Value 1 8, T.Value -1 10, T.Value -1 1, T.Value -20 0] - small_vec.sort order=Sort_Direction.Descending . should_equal small_expected + small_vec.sort Sort_Direction.Descending . should_equal small_expected Test.specify "should correctly propagate error through map" <| [1, 2, 3].map Error.throw . catch . should_equal 1 @@ -611,11 +617,22 @@ spec = Test.group "Vectors" <| [0, 1, 0].flat_map (i -> if i == 1 then [1, 1] else [i]) . should_equal [0, 1, 1, 0] [0, 0, 0].flat_map (i -> [i]) . should_equal [0, 0, 0] - Test.specify "should prepend elements" <| - [2, 3].prepend 1 . should_equal [1, 2, 3] - - Test.specify "should append elements" <| - [1, 2].append 3 . should_equal [1, 2, 3] + Test.specify "should allow inserting elements" <| + [2, 3].insert . should_equal [2, 3, Nothing] + [2, 3].insert item=1 . should_equal [2, 3, 1] + [2, 3].insert 100 item=1 . should_fail_with Index_Out_Of_Bounds.Error + [2, 3].insert 0 item=1 . should_equal [1, 2, 3] + [2, 3].insert 0 . should_equal [Nothing, 2, 3] + [2, 3].insert 2 . should_equal [2, 3, Nothing] + [1, 2, 3].insert -1 item=4 . should_equal [1, 2, 4, 3] + [1, 2, 3].insert -20 item=4 . should_fail_with Index_Out_Of_Bounds.Error + + Test.specify "should allow removing elements" <| + [1, 2, 3].remove . should_equal [1, 2] + [1, 2, 3].remove 100 . should_fail_with Index_Out_Of_Bounds.Error + [1, 2, 3].remove -123 . should_fail_with Index_Out_Of_Bounds.Error + [1, 2, 3].remove 0 . should_equal [2, 3] + [1, 2, 3].remove -1 . should_equal [1, 2] Test.specify "should return a vector containing only unique elements" <| [1, 3, 1, 2, 2, 1].distinct . should_equal [1, 3, 2] diff --git a/test/Tests/src/Random_Spec.enso b/test/Tests/src/Random_Spec.enso index 8dd57e7299e5..80c10e302175 100644 --- a/test/Tests/src/Random_Spec.enso +++ b/test/Tests/src/Random_Spec.enso @@ -1,4 +1,5 @@ from Standard.Base import all +import Standard.Base.Error.Illegal_Argument.Illegal_Argument import Standard.Base.Random @@ -6,6 +7,36 @@ from Standard.Test import Test, Test_Suite import Standard.Test.Extensions spec = Test.group "Random" <| + ## Random number generator seeded to make the test deterministic + + Test.specify "should allow generating random booleans" <| + rng = Random.new 0 + 0.up_to 3 . map _->rng.boolean . should_equal [True, True, False] + + Test.specify "should allow generating random integers" <| + rng = Random.new 12345 + rng.integer . should_equal 51 + rng.integer 0 10000 . should_equal 9080 + rng.integer 0 100000000000000 . should_fail_with Illegal_Argument.Error + + random_range = 0.up_to 1000 . map _->rng.integer . compute_bulk [Statistic.Minimum, Statistic.Maximum] + (random_range.at 0 >= 0) . should_equal True + (random_range.at 1 <= 100) . should_equal True + + Test.specify "should allow generating random decimals" <| + rng = Random.new 12345 + rng.decimal . should_equal 0.3618031071604718 epsilon=0.00000001 + rng.decimal . should_equal 0.932993485288541 epsilon=0.00000001 + + random_range = 0.up_to 1000 . map _->rng.decimal . compute_bulk [Statistic.Minimum, Statistic.Maximum] + (random_range.at 0 >= 0) . should_equal True + (random_range.at 1 <= 1) . should_equal True + + Test.specify "should allow generating random gaussian decimals" <| + rng = Random.new 12345 + rng.gaussian . should_equal -0.187808989658912 epsilon=0.00000001 + rng.gaussian . should_equal 0.5884363051154796 epsilon=0.00000001 + Test.specify "should allow to generate random indices" <| rng = Random.new 0 two_out_of_three = 0.up_to 100 . map _-> diff --git a/test/Tests/src/Semantic/Warnings_Spec.enso b/test/Tests/src/Semantic/Warnings_Spec.enso index 1896a3386e75..f1ff12a60d81 100644 --- a/test/Tests/src/Semantic/Warnings_Spec.enso +++ b/test/Tests/src/Semantic/Warnings_Spec.enso @@ -128,14 +128,14 @@ spec = Test.group "Dataflow Warnings" <| Test.specify "should attach correct stacktraces" <| current = Runtime.get_stack_trace warned = foo "value" - warning_stack = Warning.get_all warned . head . origin + warning_stack = Warning.get_all warned . first . origin relevant = warning_stack . drop (Last current.length) relevant.map .name . should_equal (['baz', 'bar', 'foo'].map ('Warnings_Spec.'+)) Test.specify "should attach reassignment info in the last-reassigned-first order" <| x = Warning.attach "warn!" 1 r = reassign_test x - warn = Warning.get_all r . head + warn = Warning.get_all r . first reassignments = warn.reassignments.map .name reassignments.should_equal ['Warnings_Spec.poly_sum', 'Small_Integer.+', 'Warnings_Spec.get_foo', 'Wrap.Value', 'Warnings_Spec.unwrap', 'Warnings_Spec.rewrap', 'Wrap.Value']