From 05e515b95c421f276f1de05a3c5d5e2d6990bbff Mon Sep 17 00:00:00 2001 From: Louis Pilfold Date: Sun, 22 Dec 2024 10:58:35 +0000 Subject: [PATCH] Remove deprecated --- CHANGELOG.md | 1 + src/gleam/iterator.gleam | 1680 -------------------------------- src/gleam/queue.gleam | 303 ------ src/gleam/regex.gleam | 210 ---- test/gleam/iterator_test.gleam | 732 -------------- test/gleam/queue_test.gleam | 342 ------- test/gleam/regex_test.gleam | 187 ---- 7 files changed, 1 insertion(+), 3454 deletions(-) delete mode 100644 src/gleam/iterator.gleam delete mode 100644 src/gleam/queue.gleam delete mode 100644 src/gleam/regex.gleam delete mode 100644 test/gleam/iterator_test.gleam delete mode 100644 test/gleam/queue_test.gleam delete mode 100644 test/gleam/regex_test.gleam diff --git a/CHANGELOG.md b/CHANGELOG.md index 578da59fa..44fa101e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - The `dynamic/decode` module has been added. This module will replace the dynamic decoding combinators from `dynamic` (`decode3`, etc) in future. +- The deprecated `iterator`, `regex`, and `queue` modules have been removed. ## v0.49.0 - 2024-12-19 diff --git a/src/gleam/iterator.gleam b/src/gleam/iterator.gleam deleted file mode 100644 index 022cda4f8..000000000 --- a/src/gleam/iterator.gleam +++ /dev/null @@ -1,1680 +0,0 @@ -import gleam/dict.{type Dict} -import gleam/int -import gleam/list -import gleam/option.{type Option, None, Some} -import gleam/order - -// Internal private representation of an Iterator -type Action(element) { - // Dedicated to Electric Six - // https://youtu.be/_30t2dzEgiw?t=162 - Stop - Continue(element, fn() -> Action(element)) -} - -/// An iterator is a lazily evaluated sequence of element. -/// -/// Iterators are useful when working with collections that are too large to -/// fit in memory (or those that are infinite in size) as they only require the -/// elements currently being processed to be in memory. -/// -/// As a lazy data structure no work is done when an iterator is filtered, -/// mapped, etc, instead a new iterator is returned with these transformations -/// applied to the stream. Once the stream has all the required transformations -/// applied it can be evaluated using functions such as `fold` and `to_list`. -/// -@deprecated("Please use the gleam_yielder package instead") -pub opaque type Iterator(element) { - Iterator(continuation: fn() -> Action(element)) -} - -// Public API for iteration -@deprecated("Please use the gleam_yielder package instead") -pub type Step(element, accumulator) { - Next(element: element, accumulator: accumulator) - Done -} - -// Shortcut for an empty iterator. -fn stop() -> Action(element) { - Stop -} - -/// Creates an iterator from a given function and accumulator. -/// -/// The function is called on the accumulator and returns either `Done`, -/// indicating the iterator has no more elements, or `Next` which contains a -/// new element and accumulator. The element is yielded by the iterator and the -/// new accumulator is used with the function to compute the next element in -/// the sequence. -/// -/// ## Examples -/// -/// ```gleam -/// unfold(from: 5, with: fn(n) { -/// case n { -/// 0 -> Done -/// n -> Next(element: n, accumulator: n - 1) -/// } -/// }) -/// |> to_list -/// // -> [5, 4, 3, 2, 1] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn unfold( - from initial: acc, - with f: fn(acc) -> Step(element, acc), -) -> Iterator(element) { - initial - |> unfold_loop(f) - |> Iterator -} - -// Creating Iterators -fn unfold_loop( - initial: acc, - f: fn(acc) -> Step(element, acc), -) -> fn() -> Action(element) { - fn() { - case f(initial) { - Next(x, acc) -> Continue(x, unfold_loop(acc, f)) - Done -> Stop - } - } -} - -/// Creates an iterator that yields values created by calling a given function -/// repeatedly. -/// -/// ```gleam -/// repeatedly(fn() { 7 }) -/// |> take(3) -/// |> to_list -/// // -> [7, 7, 7] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn repeatedly(f: fn() -> element) -> Iterator(element) { - unfold(Nil, fn(_) { Next(f(), Nil) }) -} - -/// Creates an iterator that returns the same value infinitely. -/// -/// ## Examples -/// -/// ```gleam -/// repeat(10) -/// |> take(4) -/// |> to_list -/// // -> [10, 10, 10, 10] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn repeat(x: element) -> Iterator(element) { - repeatedly(fn() { x }) -} - -/// Creates an iterator that yields each element from the given list. -/// -/// ## Examples -/// -/// ```gleam -/// from_list([1, 2, 3, 4]) -/// |> to_list -/// // -> [1, 2, 3, 4] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn from_list(list: List(element)) -> Iterator(element) { - let yield = fn(acc) { - case acc { - [] -> Done - [head, ..tail] -> Next(head, tail) - } - } - unfold(list, yield) -} - -// Consuming Iterators -fn transform_loop( - continuation: fn() -> Action(a), - state: acc, - f: fn(acc, a) -> Step(b, acc), -) -> fn() -> Action(b) { - fn() { - case continuation() { - Stop -> Stop - Continue(el, next) -> - case f(state, el) { - Done -> Stop - Next(yield, next_state) -> - Continue(yield, transform_loop(next, next_state, f)) - } - } - } -} - -/// Creates an iterator from an existing iterator -/// and a stateful function that may short-circuit. -/// -/// `f` takes arguments `acc` for current state and `el` for current element from underlying iterator, -/// and returns either `Next` with yielded element and new state value, or `Done` to halt the iterator. -/// -/// ## Examples -/// -/// Approximate implementation of `index` in terms of `transform`: -/// -/// ```gleam -/// from_list(["a", "b", "c"]) -/// |> transform(0, fn(i, el) { Next(#(i, el), i + 1) }) -/// |> to_list -/// // -> [#(0, "a"), #(1, "b"), #(2, "c")] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn transform( - over iterator: Iterator(a), - from initial: acc, - with f: fn(acc, a) -> Step(b, acc), -) -> Iterator(b) { - transform_loop(iterator.continuation, initial, f) - |> Iterator -} - -/// Reduces an iterator of elements into a single value by calling a given -/// function on each element in turn. -/// -/// If called on an iterator of infinite length then this function will never -/// return. -/// -/// If you do not care about the end value and only wish to evaluate the -/// iterator for side effects consider using the `run` function instead. -/// -/// ## Examples -/// -/// ```gleam -/// from_list([1, 2, 3, 4]) -/// |> fold(from: 0, with: fn(acc, element) { element + acc }) -/// // -> 10 -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn fold( - over iterator: Iterator(e), - from initial: acc, - with f: fn(acc, e) -> acc, -) -> acc { - iterator.continuation - |> fold_loop(f, initial) -} - -fn fold_loop( - continuation: fn() -> Action(e), - f: fn(acc, e) -> acc, - accumulator: acc, -) -> acc { - case continuation() { - Continue(elem, next) -> fold_loop(next, f, f(accumulator, elem)) - Stop -> accumulator - } -} - -// TODO: test -/// Evaluates all elements emitted by the given iterator. This function is useful for when -/// you wish to trigger any side effects that would occur when evaluating -/// the iterator. -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn run(iterator: Iterator(e)) -> Nil { - fold(iterator, Nil, fn(_, _) { Nil }) -} - -/// Evaluates an iterator and returns all the elements as a list. -/// -/// If called on an iterator of infinite length then this function will never -/// return. -/// -/// ## Examples -/// -/// ```gleam -/// from_list([1, 2, 3]) -/// |> map(fn(x) { x * 2 }) -/// |> to_list -/// // -> [2, 4, 6] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn to_list(iterator: Iterator(element)) -> List(element) { - iterator - |> fold([], fn(acc, e) { [e, ..acc] }) - |> list.reverse -} - -/// Eagerly accesses the first value of an iterator, returning a `Next` -/// that contains the first value and the rest of the iterator. -/// -/// If called on an empty iterator, `Done` is returned. -/// -/// ## Examples -/// -/// ```gleam -/// let assert Next(first, rest) = from_list([1, 2, 3, 4]) |> step -/// -/// first -/// // -> 1 -/// -/// rest |> to_list -/// // -> [2, 3, 4] -/// ``` -/// -/// ```gleam -/// empty() |> step -/// // -> Done -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn step(iterator: Iterator(e)) -> Step(e, Iterator(e)) { - case iterator.continuation() { - Stop -> Done - Continue(e, a) -> Next(e, Iterator(a)) - } -} - -/// Creates an iterator that only yields the first `desired` elements. -/// -/// If the iterator does not have enough elements all of them are yielded. -/// -/// ## Examples -/// -/// ```gleam -/// from_list([1, 2, 3, 4, 5]) -/// |> take(up_to: 3) -/// |> to_list -/// // -> [1, 2, 3] -/// ``` -/// -/// ```gleam -/// from_list([1, 2]) -/// |> take(up_to: 3) -/// |> to_list -/// // -> [1, 2] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn take(from iterator: Iterator(e), up_to desired: Int) -> Iterator(e) { - iterator.continuation - |> take_loop(desired) - |> Iterator -} - -fn take_loop(continuation: fn() -> Action(e), desired: Int) -> fn() -> Action(e) { - fn() { - case desired > 0 { - False -> Stop - True -> - case continuation() { - Stop -> Stop - Continue(e, next) -> Continue(e, take_loop(next, desired - 1)) - } - } - } -} - -/// Evaluates and discards the first N elements in an iterator, returning a new -/// iterator. -/// -/// If the iterator does not have enough elements an empty iterator is -/// returned. -/// -/// This function does not evaluate the elements of the iterator, the -/// computation is performed when the iterator is later run. -/// -/// ## Examples -/// -/// ```gleam -/// from_list([1, 2, 3, 4, 5]) -/// |> drop(up_to: 3) -/// |> to_list -/// // -> [4, 5] -/// ``` -/// -/// ```gleam -/// from_list([1, 2]) -/// |> drop(up_to: 3) -/// |> to_list -/// // -> [] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn drop(from iterator: Iterator(e), up_to desired: Int) -> Iterator(e) { - fn() { drop_loop(iterator.continuation, desired) } - |> Iterator -} - -fn drop_loop(continuation: fn() -> Action(e), desired: Int) -> Action(e) { - case continuation() { - Stop -> Stop - Continue(e, next) -> - case desired > 0 { - True -> drop_loop(next, desired - 1) - False -> Continue(e, next) - } - } -} - -/// Creates an iterator from an existing iterator and a transformation function. -/// -/// Each element in the new iterator will be the result of calling the given -/// function on the elements in the given iterator. -/// -/// This function does not evaluate the elements of the iterator, the -/// computation is performed when the iterator is later run. -/// -/// ## Examples -/// -/// ```gleam -/// from_list([1, 2, 3]) -/// |> map(fn(x) { x * 2 }) -/// |> to_list -/// // -> [2, 4, 6] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn map(over iterator: Iterator(a), with f: fn(a) -> b) -> Iterator(b) { - iterator.continuation - |> map_loop(f) - |> Iterator -} - -fn map_loop(continuation: fn() -> Action(a), f: fn(a) -> b) -> fn() -> Action(b) { - fn() { - case continuation() { - Stop -> Stop - Continue(e, continuation) -> Continue(f(e), map_loop(continuation, f)) - } - } -} - -/// Combines two iterators into a single one using the given function. -/// -/// If an iterator is longer than the other the extra elements are dropped. -/// -/// This function does not evaluate the elements of the two iterators, the -/// computation is performed when the resulting iterator is later run. -/// -/// ## Examples -/// -/// ```gleam -/// let first = from_list([1, 2, 3]) -/// let second = from_list([4, 5, 6]) -/// map2(first, second, fn(x, y) { x + y }) |> to_list -/// // -> [5, 7, 9] -/// ``` -/// -/// ```gleam -/// let first = from_list([1, 2]) -/// let second = from_list(["a", "b", "c"]) -/// map2(first, second, fn(i, x) { #(i, x) }) |> to_list -/// // -> [#(1, "a"), #(2, "b")] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn map2( - iterator1: Iterator(a), - iterator2: Iterator(b), - with fun: fn(a, b) -> c, -) -> Iterator(c) { - map2_loop(iterator1.continuation, iterator2.continuation, fun) - |> Iterator -} - -fn map2_loop( - continuation1: fn() -> Action(a), - continuation2: fn() -> Action(b), - with fun: fn(a, b) -> c, -) -> fn() -> Action(c) { - fn() { - case continuation1() { - Stop -> Stop - Continue(a, next_a) -> - case continuation2() { - Stop -> Stop - Continue(b, next_b) -> - Continue(fun(a, b), map2_loop(next_a, next_b, fun)) - } - } - } -} - -/// Appends two iterators, producing a new iterator. -/// -/// This function does not evaluate the elements of the iterators, the -/// computation is performed when the resulting iterator is later run. -/// -/// ## Examples -/// -/// ```gleam -/// from_list([1, 2]) -/// |> append(from_list([3, 4])) -/// |> to_list -/// // -> [1, 2, 3, 4] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn append(to first: Iterator(a), suffix second: Iterator(a)) -> Iterator(a) { - fn() { append_loop(first.continuation, second.continuation) } - |> Iterator -} - -fn append_loop(first: fn() -> Action(a), second: fn() -> Action(a)) -> Action(a) { - case first() { - Continue(e, first) -> Continue(e, fn() { append_loop(first, second) }) - Stop -> second() - } -} - -/// Flattens an iterator of iterators, creating a new iterator. -/// -/// This function does not evaluate the elements of the iterator, the -/// computation is performed when the iterator is later run. -/// -/// ## Examples -/// -/// ```gleam -/// from_list([[1, 2], [3, 4]]) -/// |> map(from_list) -/// |> flatten -/// |> to_list -/// // -> [1, 2, 3, 4] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn flatten(iterator: Iterator(Iterator(a))) -> Iterator(a) { - fn() { flatten_loop(iterator.continuation) } - |> Iterator -} - -fn flatten_loop(flattened: fn() -> Action(Iterator(a))) -> Action(a) { - case flattened() { - Stop -> Stop - Continue(it, next_iterator) -> - append_loop(it.continuation, fn() { flatten_loop(next_iterator) }) - } -} - -/// Joins a list of iterators into a single iterator. -/// -/// This function does not evaluate the elements of the iterator, the -/// computation is performed when the iterator is later run. -/// -/// ## Examples -/// -/// ```gleam -/// [[1, 2], [3, 4]] -/// |> map(from_list) -/// |> concat -/// |> to_list -/// // -> [1, 2, 3, 4] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn concat(iterators: List(Iterator(a))) -> Iterator(a) { - flatten(from_list(iterators)) -} - -/// Creates an iterator from an existing iterator and a transformation function. -/// -/// Each element in the new iterator will be the result of calling the given -/// function on the elements in the given iterator and then flattening the -/// results. -/// -/// This function does not evaluate the elements of the iterator, the -/// computation is performed when the iterator is later run. -/// -/// ## Examples -/// -/// ```gleam -/// from_list([1, 2]) -/// |> flat_map(fn(x) { from_list([x, x + 1]) }) -/// |> to_list -/// // -> [1, 2, 2, 3] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn flat_map( - over iterator: Iterator(a), - with f: fn(a) -> Iterator(b), -) -> Iterator(b) { - iterator - |> map(f) - |> flatten -} - -/// Creates an iterator from an existing iterator and a predicate function. -/// -/// The new iterator will contain elements from the first iterator for which -/// the given function returns `True`. -/// -/// This function does not evaluate the elements of the iterator, the -/// computation is performed when the iterator is later run. -/// -/// ## Examples -/// -/// ```gleam -/// import gleam/int -/// -/// from_list([1, 2, 3, 4]) -/// |> filter(int.is_even) -/// |> to_list -/// // -> [2, 4] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn filter( - iterator: Iterator(a), - keeping predicate: fn(a) -> Bool, -) -> Iterator(a) { - fn() { filter_loop(iterator.continuation, predicate) } - |> Iterator -} - -fn filter_loop( - continuation: fn() -> Action(e), - predicate: fn(e) -> Bool, -) -> Action(e) { - case continuation() { - Stop -> Stop - Continue(e, iterator) -> - case predicate(e) { - True -> Continue(e, fn() { filter_loop(iterator, predicate) }) - False -> filter_loop(iterator, predicate) - } - } -} - -/// Creates an iterator from an existing iterator and a transforming predicate function. -/// -/// The new iterator will contain elements from the first iterator for which -/// the given function returns `Ok`, transformed to the value inside the `Ok`. -/// -/// This function does not evaluate the elements of the iterator, the -/// computation is performed when the iterator is later run. -/// -/// ## Examples -/// -/// ```gleam -/// import gleam/string -/// import gleam/int -/// -/// "a1b2c3d4e5f" -/// |> string.to_graphemes -/// |> from_list -/// |> filter_map(int.parse) -/// |> to_list -/// // -> [1, 2, 3, 4, 5] -/// ``` -/// -pub fn filter_map( - iterator: Iterator(a), - keeping_with f: fn(a) -> Result(b, c), -) -> Iterator(b) { - fn() { filter_map_loop(iterator.continuation, f) } - |> Iterator -} - -fn filter_map_loop( - continuation: fn() -> Action(a), - f: fn(a) -> Result(b, c), -) -> Action(b) { - case continuation() { - Stop -> Stop - Continue(e, next) -> - case f(e) { - Ok(e) -> Continue(e, fn() { filter_map_loop(next, f) }) - Error(_) -> filter_map_loop(next, f) - } - } -} - -/// Creates an iterator that repeats a given iterator infinitely. -/// -/// ## Examples -/// -/// ```gleam -/// from_list([1, 2]) -/// |> cycle -/// |> take(6) -/// |> to_list -/// // -> [1, 2, 1, 2, 1, 2] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn cycle(iterator: Iterator(a)) -> Iterator(a) { - repeat(iterator) - |> flatten -} - -/// Creates an iterator of ints, starting at a given start int and stepping by -/// one to a given end int. -/// -/// ## Examples -/// -/// ```gleam -/// range(from: 1, to: 5) |> to_list -/// // -> [1, 2, 3, 4, 5] -/// ``` -/// -/// ```gleam -/// range(from: 1, to: -2) |> to_list -/// // -> [1, 0, -1, -2] -/// ``` -/// -/// ```gleam -/// range(from: 0, to: 0) |> to_list -/// // -> [0] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn range(from start: Int, to stop: Int) -> Iterator(Int) { - case int.compare(start, stop) { - order.Eq -> once(fn() { start }) - order.Gt -> - unfold(from: start, with: fn(current) { - case current < stop { - False -> Next(current, current - 1) - True -> Done - } - }) - - order.Lt -> - unfold(from: start, with: fn(current) { - case current > stop { - False -> Next(current, current + 1) - True -> Done - } - }) - } -} - -/// Finds the first element in a given iterator for which the given function returns -/// `True`. -/// -/// Returns `Error(Nil)` if the function does not return `True` for any of the -/// elements. -/// -/// ## Examples -/// -/// ```gleam -/// find(from_list([1, 2, 3]), fn(x) { x > 2 }) -/// // -> Ok(3) -/// ``` -/// -/// ```gleam -/// find(from_list([1, 2, 3]), fn(x) { x > 4 }) -/// // -> Error(Nil) -/// ``` -/// -/// ```gleam -/// find(empty(), fn(_) { True }) -/// // -> Error(Nil) -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn find( - in haystack: Iterator(a), - one_that is_desired: fn(a) -> Bool, -) -> Result(a, Nil) { - haystack.continuation - |> find_loop(is_desired) -} - -fn find_loop( - continuation: fn() -> Action(a), - f: fn(a) -> Bool, -) -> Result(a, Nil) { - case continuation() { - Stop -> Error(Nil) - Continue(e, next) -> - case f(e) { - True -> Ok(e) - False -> find_loop(next, f) - } - } -} - -/// Finds the first element in a given iterator -/// for which the given function returns `Ok(new_value)`, -/// then returns the wrapped `new_value`. -/// -/// Returns `Error(Nil)` if no such element is found. -/// -/// ## Examples -/// -/// ```gleam -/// find_map(from_list(["a", "1", "2"]), int.parse) -/// // -> Ok(1) -/// ``` -/// -/// ```gleam -/// find_map(from_list(["a", "b", "c"]), int.parse) -/// // -> Error(Nil) -/// ``` -/// -/// ```gleam -/// find_map(from_list([]), int.parse) -/// // -> Error(Nil) -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn find_map( - in haystack: Iterator(a), - one_that is_desired: fn(a) -> Result(b, c), -) -> Result(b, Nil) { - haystack.continuation - |> find_map_loop(is_desired) -} - -fn find_map_loop( - continuation: fn() -> Action(a), - f: fn(a) -> Result(b, c), -) -> Result(b, Nil) { - case continuation() { - Stop -> Error(Nil) - Continue(e, next) -> - case f(e) { - Ok(e) -> Ok(e) - Error(_) -> find_map_loop(next, f) - } - } -} - -/// Wraps values yielded from an iterator with indices, starting from 0. -/// -/// ## Examples -/// -/// ```gleam -/// from_list(["a", "b", "c"]) |> index |> to_list -/// // -> [#("a", 0), #("b", 1), #("c", 2)] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn index(over iterator: Iterator(element)) -> Iterator(#(element, Int)) { - iterator.continuation - |> index_loop(0) - |> Iterator -} - -fn index_loop( - continuation: fn() -> Action(element), - next: Int, -) -> fn() -> Action(#(element, Int)) { - fn() { - case continuation() { - Stop -> Stop - Continue(e, continuation) -> - Continue(#(e, next), index_loop(continuation, next + 1)) - } - } -} - -/// Creates an iterator that infinitely applies a function to a value. -/// -/// ## Examples -/// -/// ```gleam -/// iterate(1, fn(n) { n * 3 }) |> take(5) |> to_list -/// // -> [1, 3, 9, 27, 81] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn iterate( - from initial: element, - with f: fn(element) -> element, -) -> Iterator(element) { - unfold(initial, fn(element) { Next(element, f(element)) }) -} - -/// Creates an iterator that yields elements while the predicate returns `True`. -/// -/// ## Examples -/// -/// ```gleam -/// from_list([1, 2, 3, 2, 4]) -/// |> take_while(satisfying: fn(x) { x < 3 }) -/// |> to_list -/// // -> [1, 2] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn take_while( - in iterator: Iterator(element), - satisfying predicate: fn(element) -> Bool, -) -> Iterator(element) { - iterator.continuation - |> take_while_loop(predicate) - |> Iterator -} - -fn take_while_loop( - continuation: fn() -> Action(element), - predicate: fn(element) -> Bool, -) -> fn() -> Action(element) { - fn() { - case continuation() { - Stop -> Stop - Continue(e, next) -> - case predicate(e) { - False -> Stop - True -> Continue(e, take_while_loop(next, predicate)) - } - } - } -} - -/// Creates an iterator that drops elements while the predicate returns `True`, -/// and then yields the remaining elements. -/// -/// ## Examples -/// -/// ```gleam -/// from_list([1, 2, 3, 4, 2, 5]) -/// |> drop_while(satisfying: fn(x) { x < 4 }) -/// |> to_list -/// // -> [4, 2, 5] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn drop_while( - in iterator: Iterator(element), - satisfying predicate: fn(element) -> Bool, -) -> Iterator(element) { - fn() { drop_while_loop(iterator.continuation, predicate) } - |> Iterator -} - -fn drop_while_loop( - continuation: fn() -> Action(element), - predicate: fn(element) -> Bool, -) -> Action(element) { - case continuation() { - Stop -> Stop - Continue(e, next) -> - case predicate(e) { - False -> Continue(e, next) - True -> drop_while_loop(next, predicate) - } - } -} - -/// Creates an iterator from an existing iterator and a stateful function. -/// -/// Specifically, this behaves like `fold`, but yields intermediate results. -/// -/// ## Examples -/// -/// ```gleam -/// // Generate a sequence of partial sums -/// from_list([1, 2, 3, 4, 5]) -/// |> scan(from: 0, with: fn(acc, el) { acc + el }) -/// |> to_list -/// // -> [1, 3, 6, 10, 15] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn scan( - over iterator: Iterator(element), - from initial: acc, - with f: fn(acc, element) -> acc, -) -> Iterator(acc) { - iterator.continuation - |> scan_loop(f, initial) - |> Iterator -} - -fn scan_loop( - continuation: fn() -> Action(element), - f: fn(acc, element) -> acc, - accumulator: acc, -) -> fn() -> Action(acc) { - fn() { - case continuation() { - Stop -> Stop - Continue(el, next) -> { - let accumulated = f(accumulator, el) - Continue(accumulated, scan_loop(next, f, accumulated)) - } - } - } -} - -/// Zips two iterators together, emitting values from both -/// until the shorter one runs out. -/// -/// ## Examples -/// -/// ```gleam -/// from_list(["a", "b", "c"]) -/// |> zip(range(20, 30)) -/// |> to_list -/// // -> [#("a", 20), #("b", 21), #("c", 22)] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn zip(left: Iterator(a), right: Iterator(b)) -> Iterator(#(a, b)) { - zip_loop(left.continuation, right.continuation) - |> Iterator -} - -fn zip_loop( - left: fn() -> Action(a), - right: fn() -> Action(b), -) -> fn() -> Action(#(a, b)) { - fn() { - case left() { - Stop -> Stop - Continue(el_left, next_left) -> - case right() { - Stop -> Stop - Continue(el_right, next_right) -> - Continue(#(el_left, el_right), zip_loop(next_left, next_right)) - } - } - } -} - -// Result of collecting a single chunk by key -type Chunk(element, key) { - AnotherBy(List(element), key, element, fn() -> Action(element)) - LastBy(List(element)) -} - -/// Creates an iterator that emits chunks of elements -/// for which `f` returns the same value. -/// -/// ## Examples -/// -/// ```gleam -/// from_list([1, 2, 2, 3, 4, 4, 6, 7, 7]) -/// |> chunk(by: fn(n) { n % 2 }) -/// |> to_list -/// // -> [[1], [2, 2], [3], [4, 4, 6], [7, 7]] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn chunk( - over iterator: Iterator(element), - by f: fn(element) -> key, -) -> Iterator(List(element)) { - fn() { - case iterator.continuation() { - Stop -> Stop - Continue(e, next) -> chunk_loop(next, f, f(e), e) - } - } - |> Iterator -} - -fn chunk_loop( - continuation: fn() -> Action(element), - f: fn(element) -> key, - previous_key: key, - previous_element: element, -) -> Action(List(element)) { - case next_chunk(continuation, f, previous_key, [previous_element]) { - LastBy(chunk) -> Continue(chunk, stop) - AnotherBy(chunk, key, el, next) -> - Continue(chunk, fn() { chunk_loop(next, f, key, el) }) - } -} - -fn next_chunk( - continuation: fn() -> Action(element), - f: fn(element) -> key, - previous_key: key, - current_chunk: List(element), -) -> Chunk(element, key) { - case continuation() { - Stop -> LastBy(list.reverse(current_chunk)) - Continue(e, next) -> { - let key = f(e) - case key == previous_key { - True -> next_chunk(next, f, key, [e, ..current_chunk]) - False -> AnotherBy(list.reverse(current_chunk), key, e, next) - } - } - } -} - -/// Creates an iterator that emits chunks of given size. -/// -/// If the last chunk does not have `count` elements, it is yielded -/// as a partial chunk, with less than `count` elements. -/// -/// For any `count` less than 1 this function behaves as if it was set to 1. -/// -/// ## Examples -/// -/// ```gleam -/// from_list([1, 2, 3, 4, 5, 6]) -/// |> sized_chunk(into: 2) -/// |> to_list -/// // -> [[1, 2], [3, 4], [5, 6]] -/// ``` -/// -/// ```gleam -/// from_list([1, 2, 3, 4, 5, 6, 7, 8]) -/// |> sized_chunk(into: 3) -/// |> to_list -/// // -> [[1, 2, 3], [4, 5, 6], [7, 8]] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn sized_chunk( - over iterator: Iterator(element), - into count: Int, -) -> Iterator(List(element)) { - iterator.continuation - |> sized_chunk_loop(count) - |> Iterator -} - -fn sized_chunk_loop( - continuation: fn() -> Action(element), - count: Int, -) -> fn() -> Action(List(element)) { - fn() { - case next_sized_chunk(continuation, count, []) { - NoMore -> Stop - Last(chunk) -> Continue(chunk, stop) - Another(chunk, next_element) -> - Continue(chunk, sized_chunk_loop(next_element, count)) - } - } -} - -// Result of collecting a single sized chunk -type SizedChunk(element) { - Another(List(element), fn() -> Action(element)) - Last(List(element)) - NoMore -} - -fn next_sized_chunk( - continuation: fn() -> Action(element), - left: Int, - current_chunk: List(element), -) -> SizedChunk(element) { - case continuation() { - Stop -> - case current_chunk { - [] -> NoMore - remaining -> Last(list.reverse(remaining)) - } - Continue(e, next) -> { - let chunk = [e, ..current_chunk] - case left > 1 { - False -> Another(list.reverse(chunk), next) - True -> next_sized_chunk(next, left - 1, chunk) - } - } - } -} - -/// Creates an iterator that yields the given `elem` element -/// between elements emitted by the underlying iterator. -/// -/// ## Examples -/// -/// ```gleam -/// empty() -/// |> intersperse(with: 0) -/// |> to_list -/// // -> [] -/// ``` -/// -/// ```gleam -/// from_list([1]) -/// |> intersperse(with: 0) -/// |> to_list -/// // -> [1] -/// ``` -/// -/// ```gleam -/// from_list([1, 2, 3, 4, 5]) -/// |> intersperse(with: 0) -/// |> to_list -/// // -> [1, 0, 2, 0, 3, 0, 4, 0, 5] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn intersperse( - over iterator: Iterator(element), - with elem: element, -) -> Iterator(element) { - fn() { - case iterator.continuation() { - Stop -> Stop - Continue(e, next) -> Continue(e, fn() { intersperse_loop(next, elem) }) - } - } - |> Iterator -} - -fn intersperse_loop( - continuation: fn() -> Action(element), - separator: element, -) -> Action(element) { - case continuation() { - Stop -> Stop - Continue(e, next) -> { - let next_interspersed = fn() { intersperse_loop(next, separator) } - Continue(separator, fn() { Continue(e, next_interspersed) }) - } - } -} - -/// Returns `True` if any element emitted by the iterator satisfies the given predicate, -/// `False` otherwise. -/// -/// This function short-circuits once it finds a satisfying element. -/// -/// An empty iterator results in `False`. -/// -/// ## Examples -/// -/// ```gleam -/// empty() -/// |> any(fn(n) { n % 2 == 0 }) -/// // -> False -/// ``` -/// -/// ```gleam -/// from_list([1, 2, 5, 7, 9]) -/// |> any(fn(n) { n % 2 == 0 }) -/// // -> True -/// ``` -/// -/// ```gleam -/// from_list([1, 3, 5, 7, 9]) -/// |> any(fn(n) { n % 2 == 0 }) -/// // -> False -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn any( - in iterator: Iterator(element), - satisfying predicate: fn(element) -> Bool, -) -> Bool { - iterator.continuation - |> any_loop(predicate) -} - -fn any_loop( - continuation: fn() -> Action(element), - predicate: fn(element) -> Bool, -) -> Bool { - case continuation() { - Stop -> False - Continue(e, next) -> - case predicate(e) { - True -> True - False -> any_loop(next, predicate) - } - } -} - -/// Returns `True` if all elements emitted by the iterator satisfy the given predicate, -/// `False` otherwise. -/// -/// This function short-circuits once it finds a non-satisfying element. -/// -/// An empty iterator results in `True`. -/// -/// ## Examples -/// -/// ```gleam -/// empty() -/// |> all(fn(n) { n % 2 == 0 }) -/// // -> True -/// ``` -/// -/// ```gleam -/// from_list([2, 4, 6, 8]) -/// |> all(fn(n) { n % 2 == 0 }) -/// // -> True -/// ``` -/// -/// ```gleam -/// from_list([2, 4, 5, 8]) -/// |> all(fn(n) { n % 2 == 0 }) -/// // -> False -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn all( - in iterator: Iterator(element), - satisfying predicate: fn(element) -> Bool, -) -> Bool { - iterator.continuation - |> all_loop(predicate) -} - -fn all_loop( - continuation: fn() -> Action(element), - predicate: fn(element) -> Bool, -) -> Bool { - case continuation() { - Stop -> True - Continue(e, next) -> - case predicate(e) { - True -> all_loop(next, predicate) - False -> False - } - } -} - -/// Returns a `Dict(k, List(element))` of elements from the given iterator -/// grouped with the given key function. -/// -/// The order within each group is preserved from the iterator. -/// -/// ## Examples -/// -/// ```gleam -/// from_list([1, 2, 3, 4, 5, 6]) -/// |> group(by: fn(n) { n % 3 }) -/// // -> dict.from_list([#(0, [3, 6]), #(1, [1, 4]), #(2, [2, 5])]) -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn group( - in iterator: Iterator(element), - by key: fn(element) -> key, -) -> Dict(key, List(element)) { - iterator - |> fold(dict.new(), group_updater(key)) - |> dict.map_values(fn(_, group) { list.reverse(group) }) -} - -fn group_updater( - f: fn(element) -> key, -) -> fn(Dict(key, List(element)), element) -> Dict(key, List(element)) { - fn(groups, elem) { - groups - |> dict.upsert(f(elem), update_group_with(elem)) - } -} - -fn update_group_with(el: element) -> fn(Option(List(element))) -> List(element) { - fn(maybe_group) { - case maybe_group { - Some(group) -> [el, ..group] - None -> [el] - } - } -} - -/// This function acts similar to fold, but does not take an initial state. -/// Instead, it starts from the first yielded element -/// and combines it with each subsequent element in turn using the given function. -/// The function is called as `f(accumulator, current_element)`. -/// -/// Returns `Ok` to indicate a successful run, and `Error` if called on an empty iterator. -/// -/// ## Examples -/// -/// ```gleam -/// from_list([]) -/// |> reduce(fn(acc, x) { acc + x }) -/// // -> Error(Nil) -/// ``` -/// -/// ```gleam -/// from_list([1, 2, 3, 4, 5]) -/// |> reduce(fn(acc, x) { acc + x }) -/// // -> Ok(15) -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn reduce( - over iterator: Iterator(e), - with f: fn(e, e) -> e, -) -> Result(e, Nil) { - case iterator.continuation() { - Stop -> Error(Nil) - Continue(e, next) -> - fold_loop(next, f, e) - |> Ok - } -} - -/// Returns the last element in the given iterator. -/// -/// Returns `Error(Nil)` if the iterator is empty. -/// -/// This function runs in linear time. -/// -/// ## Examples -/// -/// ```gleam -/// empty() |> last -/// // -> Error(Nil) -/// ``` -/// -/// ```gleam -/// range(1, 10) |> last -/// // -> Ok(10) -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn last(iterator: Iterator(element)) -> Result(element, Nil) { - iterator - |> reduce(fn(_, elem) { elem }) -} - -/// Creates an iterator that yields no elements. -/// -/// ## Examples -/// -/// ```gleam -/// empty() |> to_list -/// // -> [] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn empty() -> Iterator(element) { - Iterator(stop) -} - -/// Creates an iterator that yields exactly one element provided by calling the given function. -/// -/// ## Examples -/// -/// ```gleam -/// once(fn() { 1 }) |> to_list -/// // -> [1] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn once(f: fn() -> element) -> Iterator(element) { - fn() { Continue(f(), stop) } - |> Iterator -} - -/// Creates an iterator that yields the given element exactly once. -/// -/// ## Examples -/// -/// ```gleam -/// single(1) |> to_list -/// // -> [1] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn single(elem: element) -> Iterator(element) { - once(fn() { elem }) -} - -/// Creates an iterator that alternates between the two given iterators -/// until both have run out. -/// -/// ## Examples -/// -/// ```gleam -/// from_list([1, 2, 3, 4]) -/// |> interleave(from_list([11, 12, 13, 14])) -/// |> to_list -/// // -> [1, 11, 2, 12, 3, 13, 4, 14] -/// ``` -/// -/// ```gleam -/// from_list([1, 2, 3, 4]) -/// |> interleave(from_list([100])) -/// |> to_list -/// // -> [1, 100, 2, 3, 4] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn interleave( - left: Iterator(element), - with right: Iterator(element), -) -> Iterator(element) { - fn() { interleave_loop(left.continuation, right.continuation) } - |> Iterator -} - -fn interleave_loop( - current: fn() -> Action(element), - next: fn() -> Action(element), -) -> Action(element) { - case current() { - Stop -> next() - Continue(e, next_other) -> - Continue(e, fn() { interleave_loop(next, next_other) }) - } -} - -/// Like `fold`, `fold_until` reduces an iterator of elements into a single value by calling a given -/// function on each element in turn, but uses `list.ContinueOrStop` to determine -/// whether or not to keep iterating. -/// -/// If called on an iterator of infinite length then this function will only ever -/// return if the function returns `list.Stop`. -/// -/// ## Examples -/// -/// ```gleam -/// import gleam/list -/// -/// let f = fn(acc, e) { -/// case e { -/// _ if e < 4 -> list.Continue(e + acc) -/// _ -> list.Stop(acc) -/// } -/// } -/// -/// from_list([1, 2, 3, 4]) -/// |> fold_until(from: 0, with: f) -/// // -> 6 -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn fold_until( - over iterator: Iterator(e), - from initial: acc, - with f: fn(acc, e) -> list.ContinueOrStop(acc), -) -> acc { - iterator.continuation - |> fold_until_loop(f, initial) -} - -fn fold_until_loop( - continuation: fn() -> Action(e), - f: fn(acc, e) -> list.ContinueOrStop(acc), - accumulator: acc, -) -> acc { - case continuation() { - Stop -> accumulator - Continue(elem, next) -> - case f(accumulator, elem) { - list.Continue(accumulator) -> fold_until_loop(next, f, accumulator) - list.Stop(accumulator) -> accumulator - } - } -} - -/// A variant of fold that might fail. -/// -/// The folding function should return `Result(accumulator, error)`. -/// If the returned value is `Ok(accumulator)` try_fold will try the next value in the iterator. -/// If the returned value is `Error(error)` try_fold will stop and return that error. -/// -/// ## Examples -/// -/// ```gleam -/// from_list([1, 2, 3, 4]) -/// |> try_fold(0, fn(acc, i) { -/// case i < 3 { -/// True -> Ok(acc + i) -/// False -> Error(Nil) -/// } -/// }) -/// // -> Error(Nil) -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn try_fold( - over iterator: Iterator(e), - from initial: acc, - with f: fn(acc, e) -> Result(acc, err), -) -> Result(acc, err) { - iterator.continuation - |> try_fold_loop(f, initial) -} - -fn try_fold_loop( - over continuation: fn() -> Action(a), - with f: fn(acc, a) -> Result(acc, err), - from accumulator: acc, -) -> Result(acc, err) { - case continuation() { - Stop -> Ok(accumulator) - Continue(elem, next) -> { - case f(accumulator, elem) { - Ok(result) -> try_fold_loop(next, f, result) - Error(_) as error -> error - } - } - } -} - -/// Returns the first element yielded by the given iterator, if it exists, -/// or `Error(Nil)` otherwise. -/// -/// ## Examples -/// -/// ```gleam -/// from_list([1, 2, 3]) |> first -/// // -> Ok(1) -/// ``` -/// -/// ```gleam -/// empty() |> first -/// // -> Error(Nil) -/// ``` -@deprecated("Please use the gleam_yielder package instead") -pub fn first(from iterator: Iterator(e)) -> Result(e, Nil) { - case iterator.continuation() { - Stop -> Error(Nil) - Continue(e, _) -> Ok(e) - } -} - -/// Returns nth element yielded by the given iterator, where `0` means the first element. -/// -/// If there are not enough elements in the iterator, `Error(Nil)` is returned. -/// -/// For any `index` less than `0` this function behaves as if it was set to `0`. -/// -/// ## Examples -/// -/// ```gleam -/// from_list([1, 2, 3, 4]) |> at(2) -/// // -> Ok(3) -/// ``` -/// -/// ```gleam -/// from_list([1, 2, 3, 4]) |> at(4) -/// // -> Error(Nil) -/// ``` -/// -/// ```gleam -/// empty() |> at(0) -/// // -> Error(Nil) -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn at(in iterator: Iterator(e), get index: Int) -> Result(e, Nil) { - iterator - |> drop(index) - |> first -} - -/// Counts the number of elements in the given iterator. -/// -/// This function has to traverse the entire iterator to count its elements, -/// so it runs in linear time. -/// -/// ## Examples -/// -/// ```gleam -/// empty() |> length -/// // -> 0 -/// ``` -/// -/// ```gleam -/// from_list([1, 2, 3, 4]) |> length -/// // -> 4 -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn length(over iterator: Iterator(e)) -> Int { - iterator.continuation - |> length_loop(0) -} - -fn length_loop(over continuation: fn() -> Action(e), with length: Int) -> Int { - case continuation() { - Stop -> length - Continue(_, next) -> length_loop(next, length + 1) - } -} - -/// Traverse an iterator, calling a function on each element. -/// -/// ## Examples -/// -/// ```gleam -/// empty() |> each(io.println) -/// // -> Nil -/// ``` -/// -/// ```gleam -/// from_list(["Tom", "Malory", "Louis"]) |> each(io.println) -/// // -> Nil -/// // Tom -/// // Malory -/// // Louis -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn each(over iterator: Iterator(a), with f: fn(a) -> b) -> Nil { - iterator - |> map(f) - |> run -} - -/// Add a new element to the start of an iterator. -/// -/// This function is for use with `use` expressions, to replicate the behaviour -/// of the `yield` keyword found in other languages. -/// -/// ## Examples -/// -/// ```gleam -/// let iterator = { -/// use <- yield(1) -/// use <- yield(2) -/// use <- yield(3) -/// empty() -/// } -/// -/// iterator |> to_list -/// // -> [1, 2, 3] -/// ``` -/// -@deprecated("Please use the gleam_yielder package instead") -pub fn yield(element: a, next: fn() -> Iterator(a)) -> Iterator(a) { - Iterator(fn() { Continue(element, fn() { next().continuation() }) }) -} diff --git a/src/gleam/queue.gleam b/src/gleam/queue.gleam deleted file mode 100644 index 7843b5603..000000000 --- a/src/gleam/queue.gleam +++ /dev/null @@ -1,303 +0,0 @@ -import gleam/list - -/// A queue is an ordered collection of elements. It is similar to a list, but -/// unlike a list elements can be added to or removed from either the front or -/// the back in a performant fashion. -/// -/// The internal representation may be different for two queues with the same -/// elements in the same order if the queues were constructed in different -/// ways. This is the price paid for a queue's fast access at both the front -/// and the back. -/// -/// Because of unpredictable internal representation the equality operator `==` -/// may return surprising results, and the `is_equal` and `is_logically_equal` -/// functions are the recommended way to test queues for equality. -/// -@deprecated("Please use the gleam_deque package instead") -pub opaque type Queue(a) { - Queue(in: List(a), out: List(a)) -} - -/// Creates a fresh queue that contains no values. -/// -@deprecated("Please use the gleam_deque package instead") -pub fn new() -> Queue(a) { - Queue(in: [], out: []) -} - -/// Converts a list of elements into a queue of the same elements in the same -/// order. The first element in the list becomes the front element in the queue. -/// -/// This function runs in constant time. -/// -/// # Examples -/// -/// ```gleam -/// [1, 2, 3] |> from_list |> length -/// // -> 3 -/// ``` -/// -@deprecated("Please use the gleam_deque package instead") -pub fn from_list(list: List(a)) -> Queue(a) { - Queue(in: [], out: list) -} - -/// Converts a queue of elements into a list of the same elements in the same -/// order. The front element in the queue becomes the first element in the list. -/// -/// This function runs in linear time. -/// -/// # Examples -/// -/// ```gleam -/// new() |> push_back(1) |> push_back(2) |> to_list -/// // -> [1, 2] -/// ``` -/// -@deprecated("Please use the gleam_deque package instead") -pub fn to_list(queue: Queue(a)) -> List(a) { - queue.out - |> list.append(list.reverse(queue.in)) -} - -/// Determines whether or not the queue is empty. -/// -/// This function runs in constant time. -/// -/// ## Examples -/// -/// ```gleam -/// [] |> from_list |> is_empty -/// // -> True -/// ``` -/// -/// ```gleam -/// [1] |> from_list |> is_empty -/// // -> False -/// ``` -/// -/// ```gleam -/// [1, 2] |> from_list |> is_empty -/// // -> False -/// ``` -/// -@deprecated("Please use the gleam_deque package instead") -pub fn is_empty(queue: Queue(a)) -> Bool { - queue.in == [] && queue.out == [] -} - -/// Counts the number of elements in a given queue. -/// -/// This function has to traverse the queue to determine the number of elements, -/// so it runs in linear time. -/// -/// ## Examples -/// -/// ```gleam -/// length(from_list([])) -/// // -> 0 -/// ``` -/// -/// ```gleam -/// length(from_list([1])) -/// // -> 1 -/// ``` -/// -/// ```gleam -/// length(from_list([1, 2])) -/// // -> 2 -/// ``` -/// -@deprecated("Please use the gleam_deque package instead") -pub fn length(queue: Queue(a)) -> Int { - list.length(queue.in) + list.length(queue.out) -} - -/// Pushes an element onto the back of the queue. -/// -/// # Examples -/// -/// ```gleam -/// [1, 2] |> from_list |> push_back(3) |> to_list -/// // -> [1, 2, 3] -/// ``` -/// -@deprecated("Please use the gleam_deque package instead") -pub fn push_back(onto queue: Queue(a), this item: a) -> Queue(a) { - Queue(in: [item, ..queue.in], out: queue.out) -} - -/// Pushes an element onto the front of the queue. -/// -/// # Examples -/// -/// ```gleam -/// [0, 0] |> from_list |> push_front(1) |> to_list -/// // -> [1, 0, 0] -/// ``` -/// -@deprecated("Please use the gleam_deque package instead") -pub fn push_front(onto queue: Queue(a), this item: a) -> Queue(a) { - Queue(in: queue.in, out: [item, ..queue.out]) -} - -/// Gets the last element from the queue, returning the -/// element and a new queue without that element. -/// -/// This function typically runs in constant time, but will occasionally run in -/// linear time. -/// -/// # Examples -/// -/// ```gleam -/// new() -/// |> push_back(0) -/// |> push_back(1) -/// |> pop_back -/// // -> Ok(#(1, push_front(new(), 0))) -/// ``` -/// -/// ```gleam -/// new() -/// |> push_front(0) -/// |> pop_back -/// // -> Ok(#(0, new())) -/// ``` -/// -/// ```gleam -/// new() |> pop_back -/// // -> Error(Nil) -/// ``` -/// -@deprecated("Please use the gleam_deque package instead") -pub fn pop_back(from queue: Queue(a)) -> Result(#(a, Queue(a)), Nil) { - case queue { - Queue(in: [], out: []) -> Error(Nil) - Queue(in: [], out: out) -> pop_back(Queue(in: list.reverse(out), out: [])) - Queue(in: [first, ..rest], out: out) -> { - let queue = Queue(in: rest, out: out) - Ok(#(first, queue)) - } - } -} - -/// Gets the first element from the queue, returning the -/// element and a new queue without that element. -/// -/// This function typically runs in constant time, but will occasionally run in -/// linear time. -/// -/// # Examples -/// -/// ```gleam -/// new() -/// |> push_front(1) -/// |> push_front(0) -/// |> pop_front -/// // -> Ok(#(0, push_back(new(), 1))) -/// ``` -/// -/// ```gleam -/// new() -/// |> push_back(0) -/// |> pop_front -/// // -> Ok(#(0, new())) -/// ``` -/// -/// ```gleam -/// new() |> pop_back -/// // -> Error(Nil) -/// ``` -/// -@deprecated("Please use the gleam_deque package instead") -pub fn pop_front(from queue: Queue(a)) -> Result(#(a, Queue(a)), Nil) { - case queue { - Queue(in: [], out: []) -> Error(Nil) - Queue(in: in, out: []) -> pop_front(Queue(in: [], out: list.reverse(in))) - Queue(in: in, out: [first, ..rest]) -> { - let queue = Queue(in: in, out: rest) - Ok(#(first, queue)) - } - } -} - -/// Creates a new queue from a given queue containing the same elements, but in -/// the opposite order. -/// -/// This function runs in constant time. -/// -/// ## Examples -/// -/// ```gleam -/// [] |> from_list |> reverse |> to_list -/// // -> [] -/// ``` -/// -/// ```gleam -/// [1] |> from_list |> reverse |> to_list -/// // -> [1] -/// ``` -/// -/// ```gleam -/// [1, 2] |> from_list |> reverse |> to_list -/// // -> [2, 1] -/// ``` -/// -@deprecated("Please use the gleam_deque package instead") -pub fn reverse(queue: Queue(a)) -> Queue(a) { - Queue(in: queue.out, out: queue.in) -} - -/// Checks whether two queues have equal elements in the same order, where the -/// equality of elements is determined by a given equality checking function. -/// -/// This function is useful as the internal representation may be different for -/// two queues with the same elements in the same order depending on how they -/// were constructed, so the equality operator `==` may return surprising -/// results. -/// -/// This function runs in linear time multiplied by the time taken by the -/// element equality checking function. -/// -@deprecated("Please use the gleam_deque package instead") -pub fn is_logically_equal( - a: Queue(a), - to b: Queue(a), - checking element_is_equal: fn(a, a) -> Bool, -) -> Bool { - check_equal(a.out, a.in, b.out, b.in, element_is_equal) -} - -fn check_equal( - xs: List(a), - x_tail: List(a), - ys: List(a), - y_tail: List(a), - eq: fn(a, a) -> Bool, -) -> Bool { - case xs, x_tail, ys, y_tail { - [], [], [], [] -> True - [x, ..xs], _, [y, ..ys], _ -> - case eq(x, y) { - False -> False - True -> check_equal(xs, x_tail, ys, y_tail, eq) - } - [], [_, ..], _, _ -> check_equal(list.reverse(x_tail), [], ys, y_tail, eq) - _, _, [], [_, ..] -> check_equal(xs, x_tail, list.reverse(y_tail), [], eq) - _, _, _, _ -> False - } -} - -/// Checks whether two queues have the same elements in the same order. -/// -/// This function is useful as the internal representation may be different for -/// two queues with the same elements in the same order depending on how they -/// were constructed, so the equality operator `==` may return surprising -/// results. -/// -/// This function runs in linear time. -/// -@deprecated("Please use the gleam_deque package instead") -pub fn is_equal(a: Queue(a), to b: Queue(a)) -> Bool { - check_equal(a.out, a.in, b.out, b.in, fn(a, b) { a == b }) -} diff --git a/src/gleam/regex.gleam b/src/gleam/regex.gleam deleted file mode 100644 index 6c0d1ccd6..000000000 --- a/src/gleam/regex.gleam +++ /dev/null @@ -1,210 +0,0 @@ -//// This module contains regular expression matching functions for strings. -//// The matching algorithms of the library are based on the PCRE library, but not -//// all of the PCRE library is interfaced and some parts of the library go beyond -//// what PCRE offers. Currently PCRE version 8.40 (release date 2017-01-11) is used. - -import gleam/option.{type Option} - -@deprecated("Please use the gleam_regexp package instead") -pub type Regex - -/// The details about a particular match: -/// -@deprecated("Please use the gleam_regexp package instead") -pub type Match { - Match( - /// The full string of the match. - content: String, - /// A `Regex` can have subpatterns, sup-parts that are in parentheses. - submatches: List(Option(String)), - ) -} - -/// When a regular expression fails to compile: -/// -@deprecated("Please use the gleam_regexp package instead") -pub type CompileError { - CompileError( - /// The problem encountered that caused the compilation to fail - error: String, - /// The byte index into the string to where the problem was found - /// This value may not be correct in JavaScript environments. - byte_index: Int, - ) -} - -@deprecated("Please use the gleam_regexp package instead") -pub type Options { - Options(case_insensitive: Bool, multi_line: Bool) -} - -/// Creates a `Regex` with some additional options. -/// -/// ## Examples -/// -/// ```gleam -/// let options = Options(case_insensitive: False, multi_line: True) -/// let assert Ok(re) = compile("^[0-9]", with: options) -/// check(re, "abc\n123") -/// // -> True -/// ``` -/// -/// ```gleam -/// let options = Options(case_insensitive: True, multi_line: False) -/// let assert Ok(re) = compile("[A-Z]", with: options) -/// check(re, "abc123") -/// // -> True -/// ``` -/// -@deprecated("Please use the gleam_regexp package instead") -@external(erlang, "gleam_stdlib", "compile_regex") -@external(javascript, "../gleam_stdlib.mjs", "compile_regex") -pub fn compile( - pattern: String, - with options: Options, -) -> Result(Regex, CompileError) - -/// Creates a new `Regex`. -/// -/// ## Examples -/// -/// ```gleam -/// let assert Ok(re) = from_string("[0-9]") -/// check(re, "abc123") -/// // -> True -/// ``` -/// -/// ```gleam -/// check(re, "abcxyz") -/// // -> False -/// ``` -/// -/// ```gleam -/// from_string("[0-9") -/// // -> Error(CompileError( -/// // error: "missing terminating ] for character class", -/// // byte_index: 4 -/// // )) -/// ``` -/// -@deprecated("Please use the gleam_regexp package instead") -pub fn from_string(pattern: String) -> Result(Regex, CompileError) { - compile(pattern, Options(case_insensitive: False, multi_line: False)) -} - -/// Returns a boolean indicating whether there was a match or not. -/// -/// ## Examples -/// -/// ```gleam -/// let assert Ok(re) = from_string("^f.o.?") -/// check(with: re, content: "foo") -/// // -> True -/// ``` -/// -/// ```gleam -/// check(with: re, content: "boo") -/// // -> False -/// ``` -/// -@deprecated("Please use the gleam_regexp package instead") -@external(erlang, "gleam_stdlib", "regex_check") -@external(javascript, "../gleam_stdlib.mjs", "regex_check") -pub fn check(with regex: Regex, content string: String) -> Bool - -/// Splits a string. -/// -/// ## Examples -/// -/// ```gleam -/// let assert Ok(re) = from_string(" *, *") -/// split(with: re, content: "foo,32, 4, 9 ,0") -/// // -> ["foo", "32", "4", "9", "0"] -/// ``` -/// -@deprecated("Please use the gleam_regexp package instead") -@external(erlang, "gleam_stdlib", "regex_split") -@external(javascript, "../gleam_stdlib.mjs", "regex_split") -pub fn split(with regex: Regex, content string: String) -> List(String) - -/// Collects all matches of the regular expression. -/// -/// ## Examples -/// -/// ```gleam -/// let assert Ok(re) = from_string("[oi]n a (\\w+)") -/// scan(with: re, content: "I am on a boat in a lake.") -/// // -> [ -/// // Match(content: "on a boat", submatches: [Some("boat")]), -/// // Match(content: "in a lake", submatches: [Some("lake")]), -/// // ] -/// ``` -/// -/// ```gleam -/// let assert Ok(re) = regex.from_string("([+|\\-])?(\\d+)(\\w+)?") -/// scan(with: re, content: "-36") -/// // -> [ -/// // Match(content: "-36", submatches: [Some("-"), Some("36")]) -/// // ] -/// -/// scan(with: re, content: "36") -/// // -> [ -/// // Match(content: "36", submatches: [None, Some("36")]) -/// // ] -/// ``` -/// -/// ```gleam -/// let assert Ok(re) = -/// regex.from_string("var\\s*(\\w+)\\s*(int|string)?\\s*=\\s*(.*)") -/// scan(with: re, content: "var age = 32") -/// // -> [ -/// // Match( -/// // content: "var age = 32", -/// // submatches: [Some("age"), None, Some("32")], -/// // ), -/// // ] -/// ``` -/// -/// ```gleam -/// let assert Ok(re) = regex.from_string("let (\\w+) = (\\w+)") -/// scan(with: re, content: "let age = 32") -/// // -> [ -/// // Match( -/// // content: "let age = 32", -/// // submatches: [Some("age"), Some("32")], -/// // ), -/// // ] -/// -/// scan(with: re, content: "const age = 32") -/// // -> [] -/// ``` -/// -@deprecated("Please use the gleam_regexp package instead") -@external(erlang, "gleam_stdlib", "regex_scan") -@external(javascript, "../gleam_stdlib.mjs", "regex_scan") -pub fn scan(with regex: Regex, content string: String) -> List(Match) - -/// Creates a new `String` by replacing all substrings that match the regular -/// expression. -/// -/// ## Examples -/// -/// ```gleam -/// let assert Ok(re) = regex.from_string("^https://") -/// replace(each: re, in: "https://example.com", with: "www.") -/// // -> "www.example.com" -/// ``` -/// -/// ```gleam -/// let assert Ok(re) = regex.from_string("[, +-]") -/// replace(each: re, in: "a,b-c d+e", with: "/") -/// // -> "a/b/c/d/e" -/// ``` -@deprecated("Please use the gleam_regexp package instead") -@external(erlang, "gleam_stdlib", "regex_replace") -@external(javascript, "../gleam_stdlib.mjs", "regex_replace") -pub fn replace( - each pattern: Regex, - in string: String, - with substitute: String, -) -> String diff --git a/test/gleam/iterator_test.gleam b/test/gleam/iterator_test.gleam deleted file mode 100644 index f774a623e..000000000 --- a/test/gleam/iterator_test.gleam +++ /dev/null @@ -1,732 +0,0 @@ -import gleam/dict -import gleam/int -import gleam/iterator.{Done, Next} -import gleam/list -import gleam/should - -@target(erlang) -const recursion_test_cycles = 1_000_000 - -// JavaScript engines crash when exceeding a certain stack size: -// -// - Chrome 106 and NodeJS V16, V18, and V19 crash around 10_000+ -// - Firefox 106 crashes around 35_000+. -// - Safari 16 crashes around 40_000+. -@target(javascript) -const recursion_test_cycles = 40_000 - -// a |> from_list |> to_list == a -pub fn to_from_list_test() { - let testcase = fn(subject) { - subject - |> iterator.from_list - |> iterator.to_list - |> should.equal(subject) - } - - testcase([]) - testcase([1]) - testcase([1, 2]) - testcase([1, 2, 4, 8]) -} - -pub fn step_test() { - let testcase = fn(subject) { - let step = - subject - |> iterator.from_list - |> iterator.step - - case subject { - [] -> - step - |> should.equal(Done) - - [h, ..t] -> { - let assert Next(h2, t2) = step - h - |> should.equal(h2) - t2 - |> iterator.to_list - |> should.equal(t) - } - } - } - - testcase([]) - testcase([1]) - testcase([1, 2]) - testcase([1, 2, 3]) -} - -// a |> from_list |> take(n) == a |> list.take(_, n) -pub fn take_test() { - let testcase = fn(n, subject) { - subject - |> iterator.from_list - |> iterator.take(n) - |> iterator.to_list - |> should.equal(list.take(subject, n)) - } - - testcase(0, []) - testcase(1, []) - testcase(-1, []) - testcase(0, [0]) - testcase(1, [0]) - testcase(-1, [0]) - testcase(0, [0, 1, 2, 3, 4]) - testcase(1, [0, 1, 2, 3, 4]) - testcase(2, [0, 1, 2, 3, 4]) - testcase(22, [0, 1, 2, 3, 4]) -} - -pub fn transform_index_test() { - let f = fn(i, el) { Next(#(i, el), i + 1) } - - ["a", "b", "c", "d"] - |> iterator.from_list - |> iterator.transform(0, f) - |> iterator.to_list - |> should.equal([#(0, "a"), #(1, "b"), #(2, "c"), #(3, "d")]) -} - -pub fn transform_take_test() { - let f = fn(rem, el) { - case rem > 0 { - False -> Done - True -> Next(el, rem - 1) - } - } - - [1, 2, 3, 4, 5] - |> iterator.from_list - |> iterator.transform(3, f) - |> iterator.to_list - |> should.equal([1, 2, 3]) -} - -pub fn transform_take_while_test() { - let f = fn(_, el) { - case el < 3 { - True -> Next(el, Nil) - False -> Done - } - } - - [1, 2, 3, 2, 4] - |> iterator.from_list - |> iterator.transform(Nil, f) - |> iterator.to_list - |> should.equal([1, 2]) -} - -pub fn transform_scan_test() { - let f = fn(acc, el) { - let result = acc + el - Next(result, result) - } - - [1, 2, 3, 4, 5] - |> iterator.from_list - |> iterator.transform(0, f) - |> iterator.to_list - |> should.equal([1, 3, 6, 10, 15]) -} - -// a |> from_list |> fold(a, f) == a |> list.fold(_, a, f) -pub fn fold_test() { - let testcase = fn(subject, acc, f) { - subject - |> iterator.from_list - |> iterator.fold(acc, f) - |> should.equal(list.fold(subject, acc, f)) - } - - let f = fn(acc, e) { [e, ..acc] } - testcase([], [], f) - testcase([1], [], f) - testcase([1, 2, 3], [], f) - testcase([1, 2, 3, 4, 5, 6, 7, 8], [], f) -} - -// a |> from_list |> map(f) |> to_list == a |> list.map(_, f) -pub fn map_test() { - let testcase = fn(subject, f) { - subject - |> iterator.from_list - |> iterator.map(f) - |> iterator.to_list - |> should.equal(list.map(subject, f)) - } - - let f = fn(e) { e * 2 } - testcase([], f) - testcase([1], f) - testcase([1, 2, 3], f) - testcase([1, 2, 3, 4, 5, 6, 7, 8], f) -} - -// map2(from_list(a), from_list(b), f) == list.map2(a, b, f) -pub fn map2_test() { - let testcase = fn(one, other, f) { - iterator.map2(iterator.from_list(one), iterator.from_list(other), f) - |> iterator.to_list - |> should.equal(list.map2(one, other, f)) - } - - let f = fn(a, b) { a / b } - testcase([], [], f) - testcase([], [2, 10, 3], f) - testcase([10], [2, 10, 3], f) - testcase([10, 20], [2, 10, 3], f) - testcase([10, 20, 30], [2, 10, 3], f) - testcase([10, 20, 30], [2, 10], f) - testcase([10, 20, 30], [2], f) - testcase([10, 20, 30], [], f) -} - -pub fn map2_is_lazy_test() { - let one = iterator.from_list([]) - let other = iterator.once(fn() { panic as "unreachable" }) - - iterator.map2(one, other, fn(x, y) { x + y }) - |> iterator.to_list - |> should.equal([]) -} - -// a |> from_list |> flat_map(f) |> to_list == -// a |> list.map(f) |> list.map(to_list) |> list.concat -pub fn flat_map_test() { - let testcase = fn(subject, f) { - subject - |> iterator.from_list - |> iterator.flat_map(f) - |> iterator.to_list - |> should.equal( - subject - |> list.map(f) - |> list.map(iterator.to_list) - |> list.flatten, - ) - } - - let f = fn(i) { iterator.range(i, i + 2) } - - testcase([], f) - testcase([1], f) - testcase([1, 2], f) -} - -// a |> from_list |> append(from_list(b)) |> to_list == list.concat([a, b]) -pub fn append_test() { - let testcase = fn(left, right) { - left - |> iterator.from_list - |> iterator.append(iterator.from_list(right)) - |> iterator.to_list - |> should.equal(list.flatten([left, right])) - } - - testcase([], []) - testcase([1], [2]) - testcase([1, 2], [3, 4]) -} - -// a |> list.map(from_list) |> from_list |> flatten |> to_list == list.concat(a) -pub fn flatten_test() { - let testcase = fn(lists) { - lists - |> list.map(iterator.from_list) - |> iterator.from_list - |> iterator.flatten - |> iterator.to_list - |> should.equal(list.flatten(lists)) - } - - testcase([[], []]) - testcase([[1], [2]]) - testcase([[1, 2], [3, 4]]) -} - -// a |> list.map(from_list) |> concat |> to_list == list.concat(a) -pub fn concat_test() { - let testcase = fn(lists) { - lists - |> list.map(iterator.from_list) - |> iterator.concat - |> iterator.to_list - |> should.equal(list.flatten(lists)) - } - - testcase([[], []]) - testcase([[1], [2]]) - testcase([[1, 2], [3, 4]]) -} - -// a |> from_list |> filter(f) |> to_list == a |> list.filter(_, f) -pub fn filter_test() { - let testcase = fn(subject, f) { - subject - |> iterator.from_list - |> iterator.filter(f) - |> iterator.to_list - |> should.equal(list.filter(subject, f)) - } - - let even = fn(x) { x % 2 == 0 } - testcase([], even) - testcase([1], even) - testcase([1, 2], even) - testcase([1, 2, 3], even) - testcase([1, 2, 3, 4], even) - testcase([1, 2, 3, 4, 5], even) - testcase([1, 2, 3, 4, 5, 6], even) -} - -pub fn filter_map_test() { - let testcase = fn(subject, f) { - subject - |> iterator.from_list - |> iterator.filter_map(f) - |> iterator.to_list - |> should.equal(list.filter_map(subject, f)) - } - - testcase([], int.parse) - testcase(["1"], int.parse) - testcase(["1", "2", "3"], int.parse) - testcase(["1", "a", "b"], int.parse) - testcase(["l", "2", "3", "a"], int.parse) - testcase(["1", "c", "3", "a", "b"], int.parse) - testcase(["1", "20", "ten", "4", "5", "69"], int.parse) -} - -pub fn repeat_test() { - 1 - |> iterator.repeat - |> iterator.take(5) - |> iterator.to_list - |> should.equal([1, 1, 1, 1, 1]) -} - -pub fn cycle_test() { - [1, 2, 3] - |> iterator.from_list - |> iterator.cycle - |> iterator.take(9) - |> iterator.to_list - |> should.equal([1, 2, 3, 1, 2, 3, 1, 2, 3]) -} - -pub fn unfold_test() { - iterator.unfold(2, fn(acc) { iterator.Next(acc, acc * 2) }) - |> iterator.take(5) - |> iterator.to_list - |> should.equal([2, 4, 8, 16, 32]) - - iterator.unfold(2, fn(_) { iterator.Done }) - |> iterator.take(5) - |> iterator.to_list - |> should.equal([]) - - fn(n) { - case n { - 0 -> iterator.Done - n -> iterator.Next(element: n, accumulator: n - 1) - } - } - |> iterator.unfold(from: 5) - |> iterator.to_list - |> should.equal([5, 4, 3, 2, 1]) -} - -pub fn range_test() { - let testcase = fn(a, b, expected) { - iterator.range(a, b) - |> iterator.to_list - |> should.equal(expected) - } - - testcase(0, 0, [0]) - testcase(1, 1, [1]) - testcase(-1, -1, [-1]) - testcase(0, 1, [0, 1]) - testcase(0, 5, [0, 1, 2, 3, 4, 5]) - testcase(1, -5, [1, 0, -1, -2, -3, -4, -5]) -} - -pub fn drop_test() { - iterator.range(0, 10) - |> iterator.drop(5) - |> iterator.to_list - |> should.equal([5, 6, 7, 8, 9, 10]) -} - -type Cat { - Cat(id: Int) -} - -pub fn find_test() { - iterator.range(0, 10) - |> iterator.find(fn(e) { e == 5 }) - |> should.equal(Ok(5)) - - iterator.range(0, 10) - |> iterator.find(fn(e) { e > 10 }) - |> should.equal(Error(Nil)) - - iterator.empty() - |> iterator.find(fn(_x) { True }) - |> should.equal(Error(Nil)) - - iterator.unfold(Cat(id: 1), fn(cat: Cat) { - iterator.Next(cat, Cat(id: cat.id + 1)) - }) - |> iterator.find(fn(cat: Cat) { cat.id == 10 }) - |> should.equal(Ok(Cat(id: 10))) -} - -pub fn find_map_test() { - iterator.range(0, 10) - |> iterator.find_map(fn(e) { - case e == 5 { - True -> Ok(e) - False -> Error(Nil) - } - }) - |> should.equal(Ok(5)) - - iterator.range(0, 10) - |> iterator.find_map(fn(e) { - case e > 10 { - True -> Ok(e) - False -> Error(Nil) - } - }) - |> should.equal(Error(Nil)) - - iterator.empty() - |> iterator.find_map(fn(_x) { Ok(True) }) - |> should.equal(Error(Nil)) - - iterator.unfold(Cat(id: 1), fn(cat: Cat) { - iterator.Next(cat, Cat(id: cat.id + 1)) - }) - |> iterator.find_map(fn(cat: Cat) { - case cat.id == 10 { - True -> Ok(cat) - False -> Error(Nil) - } - }) - |> should.equal(Ok(Cat(id: 10))) -} - -pub fn index_test() { - iterator.from_list(["a", "b", "c"]) - |> iterator.index - |> iterator.to_list - |> should.equal([#("a", 0), #("b", 1), #("c", 2)]) -} - -pub fn iterate_test() { - fn(x) { x * 3 } - |> iterator.iterate(from: 1) - |> iterator.take(5) - |> iterator.to_list - |> should.equal([1, 3, 9, 27, 81]) -} - -pub fn take_while_test() { - iterator.from_list([1, 2, 3, 2, 4]) - |> iterator.take_while(satisfying: fn(x) { x < 3 }) - |> iterator.to_list - |> should.equal([1, 2]) -} - -pub fn drop_while_test() { - iterator.from_list([1, 2, 3, 4, 2, 5]) - |> iterator.drop_while(satisfying: fn(x) { x < 4 }) - |> iterator.to_list - |> should.equal([4, 2, 5]) -} - -pub fn scan_test() { - iterator.from_list([1, 2, 3, 4, 5]) - |> iterator.scan(from: 0, with: fn(acc, el) { acc + el }) - |> iterator.to_list - |> should.equal([1, 3, 6, 10, 15]) -} - -pub fn zip_test() { - iterator.from_list(["a", "b", "c"]) - |> iterator.zip(iterator.range(20, 30)) - |> iterator.to_list - |> should.equal([#("a", 20), #("b", 21), #("c", 22)]) -} - -pub fn chunk_test() { - iterator.from_list([1, 2, 2, 3, 4, 4, 6, 7, 7]) - |> iterator.chunk(by: fn(n) { n % 2 }) - |> iterator.to_list - |> should.equal([[1], [2, 2], [3], [4, 4, 6], [7, 7]]) -} - -pub fn sized_chunk_test() { - iterator.from_list([1, 2, 3, 4, 5, 6]) - |> iterator.sized_chunk(into: 2) - |> iterator.to_list - |> should.equal([[1, 2], [3, 4], [5, 6]]) - - iterator.from_list([1, 2, 3, 4, 5, 6, 7, 8]) - |> iterator.sized_chunk(into: 3) - |> iterator.to_list - |> should.equal([[1, 2, 3], [4, 5, 6], [7, 8]]) -} - -pub fn intersperse_test() { - iterator.empty() - |> iterator.intersperse(with: 0) - |> iterator.to_list - |> should.equal([]) - - iterator.from_list([1]) - |> iterator.intersperse(with: 0) - |> iterator.to_list - |> should.equal([1]) - - iterator.from_list([1, 2, 3, 4, 5]) - |> iterator.intersperse(with: 0) - |> iterator.to_list - |> should.equal([1, 0, 2, 0, 3, 0, 4, 0, 5]) -} - -pub fn any_test() { - iterator.empty() - |> iterator.any(satisfying: fn(n) { n % 2 == 0 }) - |> should.be_false - - iterator.from_list([1, 2, 5, 7, 9]) - |> iterator.any(satisfying: fn(n) { n % 2 == 0 }) - |> should.be_true - - iterator.from_list([1, 3, 5, 7, 9]) - |> iterator.any(satisfying: fn(n) { n % 2 == 0 }) - |> should.be_false - - // TCO test - iterator.repeat(1) - |> iterator.take(recursion_test_cycles) - |> iterator.any(satisfying: fn(n) { n % 2 == 0 }) - |> should.be_false -} - -pub fn all_test() { - iterator.empty() - |> iterator.all(satisfying: fn(n) { n % 2 == 0 }) - |> should.be_true - - iterator.from_list([2, 4, 6, 8]) - |> iterator.all(satisfying: fn(n) { n % 2 == 0 }) - |> should.be_true - - iterator.from_list([2, 4, 5, 8]) - |> iterator.all(satisfying: fn(n) { n % 2 == 0 }) - |> should.be_false - - // TCO test - iterator.repeat(0) - |> iterator.take(recursion_test_cycles) - |> iterator.all(satisfying: fn(n) { n % 2 == 0 }) - |> should.be_true -} - -pub fn group_test() { - iterator.from_list([1, 2, 3, 4, 5, 6]) - |> iterator.group(by: fn(n) { n % 3 }) - |> should.equal(dict.from_list([#(0, [3, 6]), #(1, [1, 4]), #(2, [2, 5])])) -} - -pub fn reduce_test() { - iterator.empty() - |> iterator.reduce(with: fn(acc, x) { acc + x }) - |> should.equal(Error(Nil)) - - iterator.from_list([1, 2, 3, 4, 5]) - |> iterator.reduce(with: fn(acc, x) { acc + x }) - |> should.equal(Ok(15)) -} - -pub fn last_test() { - iterator.empty() - |> iterator.last - |> should.equal(Error(Nil)) - - iterator.range(1, 10) - |> iterator.last - |> should.equal(Ok(10)) -} - -pub fn empty_test() { - iterator.empty() - |> iterator.to_list - |> should.equal([]) -} - -pub fn once_test() { - iterator.once(fn() { 1 }) - |> iterator.to_list - |> should.equal([1]) -} - -pub fn single_test() { - iterator.single(1) - |> iterator.to_list - |> should.equal([1]) -} - -pub fn interleave_test() { - iterator.from_list([1, 2, 3, 4]) - |> iterator.interleave(with: iterator.from_list([11, 12, 13, 14])) - |> iterator.to_list - |> should.equal([1, 11, 2, 12, 3, 13, 4, 14]) - - iterator.from_list([1, 2, 3, 4]) - |> iterator.interleave(with: iterator.from_list([100])) - |> iterator.to_list - |> should.equal([1, 100, 2, 3, 4]) -} - -// a |> from_list |> fold_until(acc, f) == a |> list.fold_until(acc, f) -pub fn fold_until_test() { - let testcase = fn(subject, acc, f) { - subject - |> iterator.from_list() - |> iterator.fold_until(acc, f) - |> should.equal(list.fold_until(subject, acc, f)) - } - - let f = fn(acc, e) { - case e { - _ if e < 6 -> list.Continue([e, ..acc]) - _ -> list.Stop(acc) - } - } - testcase([], [], f) - testcase([1], [], f) - testcase([1, 2, 3], [], f) - testcase([1, 2, 3, 4, 5, 6, 7, 8], [], f) - - [1, 2, 3, 4, 5, 6, 7, 8] - |> iterator.from_list() - |> iterator.fold_until([], f) - |> should.equal([5, 4, 3, 2, 1]) -} - -// a |> from_list |> try_fold(acc, f) == a |> list.try_fold(acc, f) -pub fn try_fold_test() { - let testcase = fn(subject, acc, fun) { - subject - |> iterator.from_list() - |> iterator.try_fold(acc, fun) - |> should.equal(list.try_fold(subject, acc, fun)) - } - - let f = fn(e, acc) { - case e % 2 { - 0 -> Ok(e + acc) - _ -> Error("tried to add an odd number") - } - } - testcase([], 0, f) - testcase([2, 4, 6], 0, f) - testcase([1, 2, 3], 0, f) - testcase([1, 2, 3, 4, 5, 6, 7, 8], 0, f) - - [0, 2, 4, 6] - |> iterator.from_list() - |> iterator.try_fold(0, f) - |> should.equal(Ok(12)) - - [1, 2, 3, 4] - |> iterator.from_list() - |> iterator.try_fold(0, f) - |> should.equal(Error("tried to add an odd number")) - - // TCO test - iterator.repeat(1) - |> iterator.take(recursion_test_cycles) - |> iterator.try_fold(0, fn(e, acc) { Ok(e + acc) }) -} - -pub fn first_test() { - iterator.from_list([1, 2, 3]) - |> iterator.first - |> should.equal(Ok(1)) - - iterator.empty() - |> iterator.first - |> should.equal(Error(Nil)) -} - -pub fn at_test() { - iterator.from_list([1, 2, 3, 4]) - |> iterator.at(2) - |> should.equal(Ok(3)) - - iterator.from_list([1, 2, 3, 4]) - |> iterator.at(4) - |> should.equal(Error(Nil)) - - iterator.empty() - |> iterator.at(0) - |> should.equal(Error(Nil)) -} - -pub fn length_test() { - iterator.from_list([1]) - |> iterator.length - |> should.equal(1) - - iterator.from_list([1, 2, 3, 4]) - |> iterator.length - |> should.equal(4) - - iterator.empty() - |> iterator.length - |> should.equal(0) -} - -pub fn each_test() { - use it <- iterator.each(iterator.from_list([1])) - it - |> should.equal(1) -} - -pub fn yield_test() { - let items = { - use <- iterator.yield(1) - use <- iterator.yield(2) - use <- iterator.yield(3) - iterator.empty() - } - - items - |> iterator.to_list - |> should.equal([1, 2, 3]) -} - -pub fn yield_computes_only_necessary_values_test() { - let items = { - use <- iterator.yield(1) - use <- iterator.yield(2) - use <- iterator.yield(3) - iterator.empty() - panic as "yield computed more values than necessary" - } - - items - |> iterator.take(3) - |> iterator.to_list - |> should.equal([1, 2, 3]) -} diff --git a/test/gleam/queue_test.gleam b/test/gleam/queue_test.gleam deleted file mode 100644 index 6f8465aa7..000000000 --- a/test/gleam/queue_test.gleam +++ /dev/null @@ -1,342 +0,0 @@ -import gleam/int -import gleam/list -import gleam/pair -import gleam/queue -import gleam/should - -pub fn from_and_to_list_test() { - queue.from_list([]) - |> should.equal(queue.new()) - - [1] - |> queue.from_list - |> queue.to_list - |> should.equal([1]) - - [1, 2] - |> queue.from_list - |> queue.to_list - |> should.equal([1, 2]) - - [1, 2, 3] - |> queue.from_list - |> queue.to_list - |> should.equal([1, 2, 3]) -} - -pub fn is_empty_test() { - queue.new() - |> queue.is_empty - |> should.be_true - - queue.from_list([""]) - |> queue.is_empty - |> should.be_false -} - -pub fn length_test() { - let testcase = fn(input) { - queue.from_list(input) - |> queue.length - |> should.equal(list.length(input)) - } - - testcase([]) - testcase([1]) - testcase([1, 2]) - testcase([1, 2, 1]) - testcase([1, 2, 1, 5, 2, 7, 2, 7, 8, 4, 545]) -} - -pub fn push_back_test() { - [1, 2] - |> queue.from_list - |> queue.push_back(3) - |> queue.to_list - |> should.equal([1, 2, 3]) - - queue.new() - |> queue.push_back(1) - |> queue.push_back(2) - |> queue.push_back(3) - |> queue.to_list - |> should.equal([1, 2, 3]) -} - -pub fn push_front_test() { - [2, 3] - |> queue.from_list - |> queue.push_front(1) - |> queue.push_front(0) - |> queue.to_list - |> should.equal([0, 1, 2, 3]) -} - -pub fn push_test() { - queue.new() - |> queue.push_front("b") - |> queue.push_back("x") - |> queue.push_front("a") - |> queue.push_back("y") - |> queue.to_list - |> should.equal(["a", "b", "x", "y"]) -} - -pub fn pop_back_test() { - let assert Ok(tup) = - [1, 2, 3] - |> queue.from_list - |> queue.pop_back - - tup - |> pair.first - |> should.equal(3) - - tup - |> pair.second - |> queue.is_equal(queue.from_list([1, 2])) - |> should.be_true -} - -pub fn pop_back_after_push_back_test() { - let assert Ok(tup) = - queue.new() - |> queue.push_back(1) - |> queue.push_back(2) - |> queue.push_back(3) - |> queue.pop_back - - tup - |> pair.first - |> should.equal(3) -} - -pub fn pop_back_after_push_test() { - let assert Ok(tup) = - queue.new() - |> queue.push_front("b") - |> queue.push_back("x") - |> queue.push_front("a") - |> queue.push_back("y") - |> queue.pop_back - - tup - |> pair.first - |> should.equal("y") -} - -pub fn pop_back_empty_test() { - queue.from_list([]) - |> queue.pop_back - |> should.equal(Error(Nil)) -} - -pub fn pop_front_test() { - let assert Ok(tup) = - [1, 2, 3] - |> queue.from_list - |> queue.pop_front - - tup - |> pair.first - |> should.equal(1) - - tup - |> pair.second - |> queue.is_equal(queue.from_list([2, 3])) - |> should.be_true -} - -pub fn pop_front_after_push_front_test() { - let assert Ok(tup) = - queue.new() - |> queue.push_front(3) - |> queue.push_front(2) - |> queue.push_front(1) - |> queue.pop_front - - tup - |> pair.first - |> should.equal(1) -} - -pub fn pop_front_after_push_test() { - let assert Ok(tup) = - queue.new() - |> queue.push_front("b") - |> queue.push_back("x") - |> queue.push_front("a") - |> queue.pop_front - - tup - |> pair.first - |> should.equal("a") -} - -pub fn pop_front_empty_test() { - queue.from_list([]) - |> queue.pop_front - |> should.equal(Error(Nil)) -} - -pub fn reverse_test() { - queue.from_list([1, 2, 3]) - |> queue.reverse - |> queue.to_list - |> should.equal([3, 2, 1]) - - queue.new() - |> queue.push_back(1) - |> queue.push_back(2) - |> queue.push_back(3) - |> queue.reverse - |> queue.to_list - |> should.equal([3, 2, 1]) - - queue.new() - |> queue.push_front(1) - |> queue.push_front(2) - |> queue.push_front(3) - |> queue.reverse - |> queue.to_list - |> should.equal([1, 2, 3]) - - queue.new() - |> queue.push_front(1) - |> queue.push_front(2) - |> queue.push_back(3) - |> queue.push_back(4) - |> queue.reverse - |> queue.to_list - |> should.equal([4, 3, 1, 2]) -} - -pub fn is_equal_test() { - let should_equal = fn(a, b) { - a - |> queue.is_equal(to: b) - |> should.be_true - } - - let should_not_equal = fn(a, b) { - a - |> queue.is_equal(to: b) - |> should.be_false - } - - should_equal(queue.new(), queue.new()) - - queue.new() - |> queue.push_front(1) - |> should_equal( - queue.new() - |> queue.push_back(1), - ) - - queue.new() - |> queue.push_front(1) - |> should_equal( - queue.new() - |> queue.push_front(1), - ) - - queue.new() - |> queue.push_back(1) - |> queue.push_back(2) - |> should_equal( - queue.new() - |> queue.push_front(2) - |> queue.push_front(1), - ) - - queue.new() - |> queue.push_back(1) - |> should_not_equal( - queue.new() - |> queue.push_front(2) - |> queue.push_front(1), - ) - - queue.new() - |> queue.push_back(2) - |> queue.push_back(1) - |> should_not_equal( - queue.new() - |> queue.push_front(2) - |> queue.push_front(1), - ) -} - -pub fn is_logically_equal_test() { - let both_even_or_odd = fn(a, b) { int.is_even(a) == int.is_even(b) } - - let should_equal = fn(a, b) { - a - |> queue.is_logically_equal(to: b, checking: both_even_or_odd) - |> should.be_true - } - - let should_not_equal = fn(a, b) { - a - |> queue.is_logically_equal(to: b, checking: both_even_or_odd) - |> should.be_false - } - - should_equal(queue.new(), queue.new()) - - queue.new() - |> queue.push_front(3) - |> should_equal( - queue.new() - |> queue.push_back(1), - ) - - queue.new() - |> queue.push_front(4) - |> should_equal( - queue.new() - |> queue.push_back(2), - ) - - queue.new() - |> queue.push_front(3) - |> should_equal( - queue.new() - |> queue.push_front(1), - ) - - queue.new() - |> queue.push_back(3) - |> queue.push_back(4) - |> should_equal( - queue.new() - |> queue.push_front(2) - |> queue.push_front(1), - ) - - queue.new() - |> queue.push_back(1) - |> should_not_equal( - queue.new() - |> queue.push_front(2) - |> queue.push_front(1), - ) - - queue.new() - |> queue.push_back(2) - |> queue.push_back(1) - |> should_not_equal( - queue.new() - |> queue.push_front(2) - |> queue.push_front(1), - ) - - queue.new() - |> queue.push_back(4) - |> queue.push_back(3) - |> should_not_equal( - queue.new() - |> queue.push_front(2) - |> queue.push_front(1), - ) -} diff --git a/test/gleam/regex_test.gleam b/test/gleam/regex_test.gleam deleted file mode 100644 index e51757798..000000000 --- a/test/gleam/regex_test.gleam +++ /dev/null @@ -1,187 +0,0 @@ -import gleam/option.{None, Some} -import gleam/regex.{Match, Options} -import gleam/should - -pub fn from_string_test() { - let assert Ok(re) = regex.from_string("[0-9]") - - regex.check(re, "abc123") - |> should.be_true - - regex.check(re, "abcxyz") - |> should.be_false - - let assert Error(_) = regex.from_string("[0-9") -} - -pub fn compile_test() { - let options = Options(case_insensitive: True, multi_line: False) - let assert Ok(re) = regex.compile("[A-B]", options) - - regex.check(re, "abc123") - |> should.be_true - - let options = Options(case_insensitive: False, multi_line: True) - let assert Ok(re) = regex.compile("^[0-9]", options) - - regex.check(re, "abc\n123") - |> should.be_true - - // On target Erlang this test will only pass if unicode and ucp flags are set - let assert Ok(re) = regex.compile("\\s", options) - // Em space == U+2003 == " " == used below - regex.check(re, " ") - |> should.be_true -} - -pub fn check_test() { - let assert Ok(re) = regex.from_string("^f.o.?") - - regex.check(re, "foo") - |> should.be_true - - regex.check(re, "boo") - |> should.be_false - - re - |> regex.check(content: "foo") - |> should.be_true - - "boo" - |> regex.check(with: re) - |> should.be_false - - // On target JavaScript internal `RegExp` objects are stateful when they - // have the global or sticky flags set (e.g., /foo/g or /foo/y). - // These following tests make sure that our implementation circumvents this. - let assert Ok(re) = regex.from_string("^-*[0-9]+") - - regex.check(re, "1") - |> should.be_true - - regex.check(re, "12") - |> should.be_true - - regex.check(re, "123") - |> should.be_true -} - -pub fn split_test() { - let assert Ok(re) = regex.from_string(" *, *") - - regex.split(re, "foo,32, 4, 9 ,0") - |> should.equal(["foo", "32", "4", "9", "0"]) -} - -pub fn matching_split_test() { - let assert Ok(re) = regex.from_string("([+-])( *)(d)*") - - regex.split(re, "abc+ def+ghi+ abc") - |> should.equal([ - "abc", "+", " ", "d", "ef", "+", "", "", "ghi", "+", " ", "", "abc", - ]) -} - -pub fn scan_test() { - let assert Ok(re) = regex.from_string("Gl\\w+") - - regex.scan(re, "!Gleam") - |> should.equal([Match(content: "Gleam", submatches: [])]) - - regex.scan(re, "ΰ€ΉGleam") - |> should.equal([Match(content: "Gleam", submatches: [])]) - - regex.scan(re, "𐍈Gleam") - |> should.equal([Match(content: "Gleam", submatches: [])]) - - let assert Ok(re) = regex.from_string("[oi]n a(.?) (\\w+)") - - regex.scan(re, "I am on a boat in a lake.") - |> should.equal([ - Match(content: "on a boat", submatches: [None, Some("boat")]), - Match(content: "in a lake", submatches: [None, Some("lake")]), - ]) - - let assert Ok(re) = regex.from_string("answer (\\d+)") - regex.scan(re, "Is the answer 42?") - |> should.equal([Match(content: "answer 42", submatches: [Some("42")])]) - - let assert Ok(re) = regex.from_string("(\\d+)") - regex.scan(re, "hello 42") - |> should.equal([Match(content: "42", submatches: [Some("42")])]) - - regex.scan(re, "δ½ ε₯½ 42") - |> should.equal([Match(content: "42", submatches: [Some("42")])]) - - regex.scan(re, "δ½ ε₯½ 42 δΈ–η•Œ") - |> should.equal([Match(content: "42", submatches: [Some("42")])]) - - let assert Ok(re) = regex.from_string("([+|\\-])?(\\d+)(\\w+)?") - regex.scan(re, "+36kg") - |> should.equal([ - Match(content: "+36kg", submatches: [Some("+"), Some("36"), Some("kg")]), - ]) - - regex.scan(re, "36kg") - |> should.equal([ - Match(content: "36kg", submatches: [None, Some("36"), Some("kg")]), - ]) - - regex.scan(re, "36") - |> should.equal([Match(content: "36", submatches: [None, Some("36")])]) - - regex.scan(re, "-36") - |> should.equal([Match(content: "-36", submatches: [Some("-"), Some("36")])]) - - regex.scan(re, "-kg") - |> should.equal([]) - - let assert Ok(re) = - regex.from_string("var\\s*(\\w+)\\s*(int|string)?\\s*=\\s*(.*)") - regex.scan(re, "var age int = 32") - |> should.equal([ - Match(content: "var age int = 32", submatches: [ - Some("age"), - Some("int"), - Some("32"), - ]), - ]) - - regex.scan(re, "var age = 32") - |> should.equal([ - Match(content: "var age = 32", submatches: [Some("age"), None, Some("32")]), - ]) - - let assert Ok(re) = regex.from_string("let (\\w+) = (\\w+)") - regex.scan(re, "let age = 32") - |> should.equal([ - Match(content: "let age = 32", submatches: [Some("age"), Some("32")]), - ]) - - regex.scan(re, "const age = 32") - |> should.equal([]) -} - -pub fn replace_0_test() { - let assert Ok(re) = regex.from_string(",") - regex.replace(in: "a,b,c,d", each: re, with: " ") - |> should.equal("a b c d") -} - -pub fn replace_1_test() { - let assert Ok(re) = regex.from_string("\\d") - regex.replace(in: "Hell1o, World!1", each: re, with: "") - |> should.equal("Hello, World!") -} - -pub fn replace_2_test() { - let assert Ok(re) = regex.from_string("🐈") - regex.replace(in: "🐈🐈 are great!", each: re, with: "πŸ•") - |> should.equal("πŸ•πŸ• are great!") -} - -pub fn replace_3_test() { - let assert Ok(re) = regex.from_string("🐈") - regex.replace(re, "🐈🐈 are great!", "πŸ•") - |> should.equal("πŸ•πŸ• are great!") -}