From ecbf75f1244747459b46c79240a7def515b5b545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E5=AE=87=E7=A5=A5?= Date: Mon, 22 Apr 2024 09:42:39 +0800 Subject: [PATCH] iter: minimal bare impl --- array/array.mbt | 82 +++++++++++++++++++-------- array/array.mbti | 1 + array/moon.pkg.json | 3 +- iter/consumers.mbt | 43 ++++++++++++++ iter/iter.mbti | 27 +++++++++ iter/moon.pkg.json | 7 +++ iter/operators.mbt | 133 ++++++++++++++++++++++++++++++++++++++++++++ iter/producers.mbt | 38 +++++++++++++ iter/types.mbt | 15 +++++ 9 files changed, 324 insertions(+), 25 deletions(-) create mode 100644 iter/consumers.mbt create mode 100644 iter/iter.mbti create mode 100644 iter/moon.pkg.json create mode 100644 iter/operators.mbt create mode 100644 iter/producers.mbt create mode 100644 iter/types.mbt diff --git a/array/array.mbt b/array/array.mbt index 7c0612ada..81d2cfb34 100644 --- a/array/array.mbt +++ b/array/array.mbt @@ -58,7 +58,7 @@ test "iter" { @assertion.assert_eq(i, 5)? } -/// Iterates over the array with index. +/// Iterates over the array with index. /// /// # Arguments /// @@ -150,7 +150,7 @@ test "iter_rev" { @assertion.assert_eq(i, 1)? } -/// Iterates over the array with index in reversed turn. +/// Iterates over the array with index in reversed turn. /// /// # Arguments /// @@ -162,7 +162,7 @@ test "iter_rev" { /// ``` /// [1, 2, 3, 4, 5].iter_revi(fn(index, elem){ /// print("(\(index),\(elem)) ") -/// }) //output: (4,5) (3,4) (2,3) (1,2) (0,1) +/// }) //output: (4,5) (3,4) (2,3) (1,2) (0,1) /// ``` pub fn iter_revi[T](self : Array[T], f : (Int, T) -> Unit) -> Unit { let len = self.length() @@ -238,7 +238,7 @@ test "map" { } /// Maps a function over the elements of the arr with index. -/// +/// /// # Example /// ``` /// let arr = [3, 4, 5] @@ -329,7 +329,7 @@ test "from_array" { } /// Fold out values from an array according to certain rules. -/// +/// /// # Example /// ``` /// let sum = [1, 2, 3, 4, 5].fold_left(init=0, fn { sum, elem => sum + elem }) @@ -353,7 +353,7 @@ test "fold_left" { } /// Fold out values from an array according to certain rules in reversed turn. -/// +/// /// # Example /// ``` /// let sum = [1, 2, 3, 4, 5].fold_right(init=0, fn { sum, elem => sum + elem }) @@ -377,7 +377,7 @@ test "fold_right" { } /// Fold out values from an array according to certain rules with index. -/// +/// /// # Example /// ``` /// let sum = [1, 2, 3, 4, 5].fold_lefti(init=0, fn { index, sum, elem => sum + index }) @@ -406,7 +406,7 @@ test "fold_lefti" { } /// Fold out values from an array according to certain rules in reversed turn with index. -/// +/// /// # Example /// ``` /// let sum = [1, 2, 3, 4, 5].fold_righti(init=0, fn { index, sum, elem => sum + index }) @@ -436,7 +436,7 @@ test "fold_righti" { } /// Reverses the order of elements in the slice, in place. -/// +/// /// # Example /// ``` /// let arr = [1, 2, 3, 4, 5] @@ -477,9 +477,9 @@ test "reverse" { } /// Swap two elements in the array. -/// -/// # Example -/// +/// +/// # Example +/// /// ``` /// let arr = [1, 2, 3, 4, 5] /// arr.swap(0, 1) @@ -512,9 +512,9 @@ test "swap" { } /// Check if all the elements in the array match the condition. -/// -/// # Example -/// +/// +/// # Example +/// /// ``` /// let arr = [1, 2, 3, 4, 5] /// arr.all(fn(ele) { ele < 6 }) // true @@ -546,9 +546,9 @@ test "all" { } /// Check if any of the elements in the array match the condition. -/// -/// # Example -/// +/// +/// # Example +/// /// ``` /// let arr = [1, 2, 3, 4, 5] /// arr.any(fn(ele) { ele < 6 }) // true @@ -580,7 +580,7 @@ test "any" { } /// Fill the array with a given value. -/// +/// /// # Example /// ``` /// [0, 0, 0, 0, 0].fill(3) // [3, 3, 3, 3, 3] @@ -608,7 +608,7 @@ test "fill" { } /// Search the array index for a given element. -/// +/// /// # Example /// ``` /// let arr = [3, 4, 5] @@ -642,7 +642,7 @@ test "search" { } /// Checks if the array contains an element. -/// +/// /// # Example /// ``` /// let arr = [3, 4, 5] @@ -676,7 +676,7 @@ test "contains" { } /// Check if the array starts with a given prefix. -/// +/// /// # Example /// ``` /// let arr = [3, 4, 5] @@ -719,7 +719,7 @@ test "starts_with" { } /// Check if the array ends with a given suffix. -/// +/// /// # Example /// ``` /// let v = [3, 4, 5] @@ -768,7 +768,7 @@ test "ends_with" { } /// Convert array to list. -/// +/// /// # Example /// /// ``` @@ -894,3 +894,37 @@ test "op_add" { content="[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]", )? } + +/// @intrinsic %iter.from_array +pub fn to_iter[T](self : Array[T]) -> @iter.Iter[T] { + @iter.Iter::_unstable_internal_make( + fn(yield) { + for i = 0, len = self.length(); i < len; i = i + 1 { + if yield(self[i]).not() { + break + } + } + }, + ) +} + +test "to_iter" { + let arr = [1, 2, 3, 4, 5] + let iter = arr.to_iter() + let exb = Buffer::make(0) + let mut i = 0 + iter.iter(fn(x) { + exb.write_string(x.to_string()) + exb.write_char('\n') + i = i + 1 + }) + @assertion.assert_eq(i, arr.length())? + exb.expect(~content= + #|1 + #|2 + #|3 + #|4 + #|5 + #| + )? +} diff --git a/array/array.mbti b/array/array.mbti index a5b5f93b9..d91094cd1 100644 --- a/array/array.mbti +++ b/array/array.mbti @@ -35,6 +35,7 @@ fn Array::sort_by_key[T, K : @moonbitlang/core/builtin.Compare + @moonbitlang/co fn Array::stable_sort[T : @moonbitlang/core/builtin.Compare + @moonbitlang/core/builtin.Eq](Array[T]) -> Unit fn Array::starts_with[T : @moonbitlang/core/builtin.Eq](Array[T], Array[T]) -> Bool fn Array::swap[T](Array[T], Int, Int) -> Unit +fn Array::to_iter[T](Array[T]) -> @moonbitlang/core/iter.Iter[T] fn Array::to_list[T](Array[T]) -> List[T] // Traits diff --git a/array/moon.pkg.json b/array/moon.pkg.json index d43b84a80..b88fe948e 100644 --- a/array/moon.pkg.json +++ b/array/moon.pkg.json @@ -4,6 +4,7 @@ "moonbitlang/core/assertion", "moonbitlang/core/math", "moonbitlang/core/coverage", - "moonbitlang/core/vec" + "moonbitlang/core/vec", + "moonbitlang/core/iter" ] } diff --git a/iter/consumers.mbt b/iter/consumers.mbt new file mode 100644 index 000000000..7a2bbfdef --- /dev/null +++ b/iter/consumers.mbt @@ -0,0 +1,43 @@ +// Copyright 2024 International Digital Economy Academy +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/// @intrinsic %iter.iter +pub fn iter[T](self : Iter[T], f : (T) -> Unit) -> Unit { + (self.0)( + fn { + yield => { + f(yield) + true + } + }, + ) +} + +/// @intrinsic %iter.reduce +pub fn fold[T, B](self : Iter[T], f : (B, T) -> B, init : B) -> B { + let mut acc = init + (self.0)( + fn { + yield => { + acc = f(acc, yield) + true + } + }, + ) + acc +} + +pub fn count[T](self : Iter[T]) -> Int { + self.fold(fn { acc, _ => acc + 1 }, 0) +} diff --git a/iter/iter.mbti b/iter/iter.mbti new file mode 100644 index 000000000..e38404418 --- /dev/null +++ b/iter/iter.mbti @@ -0,0 +1,27 @@ +package moonbitlang/core/iter + +// Values + +// Types and methods +type Iter +fn Iter::_unstable_internal_make[T](((T) -> Bool) -> Unit) -> Iter[T] +fn Iter::count[T](Iter[T]) -> Int +fn Iter::drop[T](Iter[T], Int) -> Iter[T] +fn Iter::drop_while[T](Iter[T], (T) -> Bool) -> Iter[T] +fn Iter::empty[T]() -> Iter[T] +fn Iter::filter[T](Iter[T], (T) -> Bool) -> Iter[T] +fn Iter::find_first[T](Iter[T], (T) -> Bool) -> Option[T] +fn Iter::flat_map[T, R](Iter[T], (T) -> Iter[R]) -> Iter[R] +fn Iter::fold[T, B](Iter[T], (B, T) -> B, B) -> B +fn Iter::iter[T](Iter[T], (T) -> Unit) -> Unit +fn Iter::map[T, R](Iter[T], (T) -> R) -> Iter[R] +fn Iter::repeat[T](T) -> Iter[T] +fn Iter::singleton[T](T) -> Iter[T] +fn Iter::take[T](Iter[T], Int) -> Iter[T] +fn Iter::take_while[T](Iter[T], (T) -> Bool) -> Iter[T] +fn Iter::tap[T](Iter[T], (T) -> Unit) -> Iter[T] + +// Traits + +// Extension Methods + diff --git a/iter/moon.pkg.json b/iter/moon.pkg.json new file mode 100644 index 000000000..144575e9d --- /dev/null +++ b/iter/moon.pkg.json @@ -0,0 +1,7 @@ +{ + "import": [ + "moonbitlang/core/builtin", + "moonbitlang/core/assertion", + "moonbitlang/core/coverage" + ] +} diff --git a/iter/operators.mbt b/iter/operators.mbt new file mode 100644 index 000000000..512de6ce2 --- /dev/null +++ b/iter/operators.mbt @@ -0,0 +1,133 @@ +// Copyright 2024 International Digital Economy Academy +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/// @intrinsic %iter.filter +pub fn filter[T](self : Iter[T], f : (T) -> Bool) -> Iter[T] { + Iter::Iter( + fn { yield => (self.0)(fn { a => if f(a) { yield(a) } else { true } }) }, + ) +} + +/// @intrinsic %iter.map +pub fn map[T, R](self : Iter[T], f : (T) -> R) -> Iter[R] { + Iter::Iter(fn { yield => (self.0)(fn { a => yield(f(a)) }) }) +} + +/// @intrinsic %iter.flat_map +pub fn flat_map[T, R](self : Iter[T], f : (T) -> Iter[R]) -> Iter[R] { + Iter::Iter( + fn { + yield => + (self.0)( + fn { + a => { + (f(a).0)(yield) + true + } + }, + ) + }, + ) +} + +pub fn tap[T](self : Iter[T], f : (T) -> Unit) -> Iter[T] { + self.iter(f) + self +} + +/// @intrinsic %iter.take +pub fn take[T](self : Iter[T], n : Int) -> Iter[T] { + Iter::Iter( + fn { + yield => { + let mut i = 0 + (self.0)( + fn { + a => + if i < n { + i = i + 1 + yield(a) + } else { + false + } + }, + ) + } + }, + ) +} + +pub fn take_while[T](self : Iter[T], f : (T) -> Bool) -> Iter[T] { + Iter::Iter( + fn { yield => (self.0)(fn { a => if f(a) { yield(a) } else { false } }) }, + ) +} + +pub fn drop[T](self : Iter[T], n : Int) -> Iter[T] { + Iter::Iter( + fn { + yield => { + let mut i = 0 + (self.0)( + fn { + a => + if i < n { + i = i + 1 + true + } else { + yield(a) + } + }, + ) + } + }, + ) +} + +pub fn drop_while[T](self : Iter[T], f : (T) -> Bool) -> Iter[T] { + Iter::Iter( + fn { + yield => { + let mut dropping = true + (self.0)( + fn { + a => + if dropping && f(a) { + true + } else { + dropping = false + yield(a) + } + }, + ) + } + }, + ) +} + +pub fn find_first[T](self : Iter[T], f : (T) -> Bool) -> Option[T] { + let mut result : Option[T] = None + (self.0)( + fn { + a => + if f(a) { + result = Some(a) + false + } else { + true + } + }, + ) + result +} diff --git a/iter/producers.mbt b/iter/producers.mbt new file mode 100644 index 000000000..72b166ff9 --- /dev/null +++ b/iter/producers.mbt @@ -0,0 +1,38 @@ +// Copyright 2024 International Digital Economy Academy +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +pub fn Iter::_unstable_internal_make[T](f : ((T) -> Bool) -> Unit) -> Iter[T] { + Iter::Iter(f) +} + +pub fn Iter::empty[T]() -> Iter[T] { + Iter::Iter(fn { _ => () }) +} + +pub fn Iter::singleton[T](a : T) -> Iter[T] { + Iter::Iter(fn { yield => ignore(yield(a)) }) +} + +/// @intrinsic %iter.cycle +pub fn Iter::repeat[T](a : T) -> Iter[T] { + Iter::Iter( + fn(yield) { + for ; ; { + if yield(a).not() { + break + } + } + }, + ) +} diff --git a/iter/types.mbt b/iter/types.mbt new file mode 100644 index 000000000..3c303606b --- /dev/null +++ b/iter/types.mbt @@ -0,0 +1,15 @@ +// Copyright 2024 International Digital Economy Academy +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +type Iter[T] ((T) -> Bool) -> Unit