// Experimental functions, maybe removed or changed in the future.
///|
/// Creates an iterator starts from init and extends by step, until `cond` returns `false`.
///
/// **Note: experimental function**
pub fn[A] seq(init~ : A, step~ : (A) -> A, cond~ : (A) -> Bool) -> T[A] {
let mut v = init
{
run: fn() {
if cond(v) {
let result = Some(v)
v = step(v)
result
} else {
None
}
},
}
}
///|
/// **Note: experimental function**
pub fn[A, S] unfold_eager(init~ : S, step~ : (S) -> (A, S)?) -> T[A] {
from_array(
loop (step(init), []) {
(Some((v, state)), arr) => continue (step(state), [..arr, v])
(None, arr) => arr
},
)
}
///|
/// **Note: experimental function**
pub fn[A, S] unfold(init~ : S, step~ : (S) -> (A, S)?) -> T[A] {
let mut state = init
{
run: fn() {
match step(state) {
Some((v, state_)) => {
state = state_
Some(v)
}
None => None
}
},
}
}
///|
test {
assert_eq(
unfold(init=20, step=fn(n) { if n >= 0 { Some((n, n - 2)) } else { None } }).collect(),
unfold_eager(init=20, step=fn(n) {
if n >= 0 {
Some((n, n - 2))
} else {
None
}
}).collect(),
) // => [20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 0]
}
///|
/// **Note: experimental function**
pub fn[A : Compare] range_by(start~ : A, end? : A, step~ : (A) -> A) -> T[A] {
let mut a = start
{
run: match end {
Some(end) =>
fn() {
if a < end {
let result = Some(a)
a = step(a)
result
} else {
None
}
}
None =>
fn() {
let result = Some(a)
a = step(a)
result
}
},
}
}
///|
/// **Note: experimental function**, related pr: https://github.com/moonbitlang/core/pull/1260
pub fn[A, E : Error] try_collect(self : T[Result[A, E]]) -> Array[A] raise E {
let array = Array::new(capacity=16)
loop self.next() {
Some(v) => {
match v {
Ok(v) => array.push(v)
Err(e) => raise e
}
continue self.next()
}
None => array
}
}
///|
/// Appends an element to the end of the iterator.
///
/// *Note*: The name might be subject to change, related issue: https://github.com/moonbitlang/core/issues/1511
pub fn[A] append(self : T[A], other : A) -> T[A] {
self.concat(singleton(other))
}
///|
/// Prepends an element to the beginning of the iterator.
///
/// *Note*: The name might be subject to change, related issue: https://github.com/moonbitlang/core/issues/1511
pub fn[A] prepend(self : T[A], other : A) -> T[A] {
singleton(other).concat(self)
}
///|
/// Splits the iterator into two parts at the first element for which `pred` returns `false`.
///
/// ## Returns
///
/// *Note that requesting the second part of the iterator will consume the first part.*
///
/// **Note: experimental function**
pub fn[A] span(self : T[A], pred : (A) -> Bool) -> (T[A], T[A]) {
let mut taken = false
let left_array = []
let mut left_i = 0
let right_array = []
let left = {
run: fn() {
if not(taken) {
match self.next() {
Some(v) =>
if pred(v) {
Some(v)
} else {
right_array.push(v)
taken = true
None
}
None => None
}
} else if left_i < left_array.length() {
let result = Some(left_array[left_i])
left_i += 1
result
} else {
None
}
},
}
let right = {
run: fn() {
if not(taken) {
loop self.next() {
Some(v) =>
if pred(v) {
left_array.push(v)
continue self.next()
} else {
taken = true
return Some(v)
}
None => None
}
} else if not(right_array.is_empty()) {
Some(right_array.remove(0))
} else {
let v = (self.run)()
v
}
},
}
(left, right)
}
///|
test {
let test_iter = range(start=1, end=20, inclusive=true)
let (left, right) = test_iter.span(fn(n) { n <= 10 })
assert_eq(left.collect(), [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
assert_eq(right.collect(), [11, 12, 13, 14, 15, 16, 17, 18, 19, 20])
let test_iter = range(start=1, end=20, inclusive=true)
let (left, right) = test_iter.span(fn(n) { n <= 10 })
assert_eq(right.collect(), [11, 12, 13, 14, 15, 16, 17, 18, 19, 20])
assert_eq(left.collect(), [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
}