export Iter(*), IntoIter(*), * use Mem # might be temporary - for test ListLike instance for range. # Basic instances inst IntoIter Ptr into-iter (self): self& into-iter() # EMPTY EmptyIter EmptyIter fn nil(): EmptyIter inst IntoIter EmptyIter into-iter (self): self inst Iter EmptyIter next(_): None # MAPPPP Map it from to Map it (from -> to) inst IntoIter Map into-iter (self Map it from to) -> Map it from to return self inst Iter Map next (Ptr(Map(it, fun))) case next(&it) None return None Just(x) return Just(fun(x)) fn map (iterable, fun) it = into-iter(iterable) return Map(it, fun) # MAPPPP MapMaybe it from to MapMaybe it (from -> Maybe to) inst IntoIter MapMaybe into-iter (self MapMaybe it from to) -> MapMaybe it from to return self inst Iter MapMaybe next (Ptr(MapMaybe(it, fun))) while True case next(&it) None return None Just(x) case fun(x) None pass Just(xx) return Just(xx) fn map-maybe (iterable, fun) it = into-iter(iterable) return MapMaybe(it, fun) ##### FILTERRRRRR Filter it item og it fun item -> Bool inst IntoIter Filter into-iter (self Filter it from) -> Filter it from return self inst Iter Filter next (self Ptr (Filter it item)) -> Maybe item <= Iter it while True case next(&self&.og) None return None Just(x) if self&.fun(x) return Just(x) # unreachable return @undefined fn filter (iterable it, fun from -> Bool) -> Filter it' from <= IntoIter it it = into-iter(iterable) return Filter { og: it, fun: fun } # DROPPPP Drop it Drop it Size inst IntoIter Drop into-iter (self Drop it) -> Drop it: self inst Iter Drop next (Ptr(Drop(it, i))) while i > 0 _ = next(&it) i <= i - 1 return next(&it) fn drop (iterable, i) it = iterable into-iter() return Drop(it, i) # Takeeee Take it Take it Size inst IntoIter Take into-iter(self): self inst Iter Take next(Ptr(Take(it, i))) if i > 0 x = next(&it) i <= i - 1 return x else return None fn take(it, i): Take(it into-iter(), i) # Bounded range Range Range I32 I32 RangeIter RangeIter Range I32 fn to (from, to): Range(from, to) fn range (from, to): Range(from, to) inst IntoIter Range into-iter (Range(from, to)): RangeIter(Range(from, to), from) inst IntoIter RangeIter into-iter (self RangeIter): self inst Iter RangeIter next (self Ptr RangeIter) -> Maybe I32 case self& RangeIter(Range(from, to), cur) if cur > to return None x = Just(cur) self <&= RangeIter(Range(from, to), cur + 1) return x # Unbounded range FromIter from I32 fn from(f): FromIter { from: f } inst IntoIter FromIter into-iter(it): it inst Iter FromIter next (Ptr(self) Ptr FromIter) -> Maybe I32 v = self.from self <.from= self.from + 1 return Just(v) # downto iterator DownToRange from I32 to I32 DownToIter dtrange DownToRange i I32 fn down-to (from, to): DownToRange { from, to } inst IntoIter DownToRange into-iter (self _): DownToIter { dtrange: self, i: self.from } inst IntoIter DownToIter into-iter (self _): self inst Iter DownToIter next (self Ptr _) -> Maybe I32 if self&.i < self&.dtrange.to return None x = Just(self&.i) self <&.i= self&.i - 1 return x Zip it it' left-it it right-it it' inst IntoIter Zip into-iter (self Zip it it'): self inst Iter Zip next (self Ptr (Zip it it')) -> Maybe (Tuple2 item item') <= Iter it, Iter it' copy = self& # kind of stupid but it works. we should not consume elements if we can't. i mean, the user should probably take care of his iter not having side effects. i guess. while True case next(©.left-it) None return None Just(left-x) case next(©.right-it) None return None Just(right-x) # consume the two (yeah, kinda funny) next(&self&.left-it) next(&self&.right-it) return Just(Tuple2(left-x, right-x)) fn zip(left, right) left-it = left into-iter() right-it = right into-iter() return Zip { left-it: left-it, right-it: right-it } ###### FLATTEN (unfinished) FlattenIter it it' super it inner it' empty Bool # hack for empty iterators. inst IntoIter FlattenIter into-iter (self): self inst Iter FlattenIter next (self) if self&.empty return None while True case next(&self&.inner) Just(x) return Just(x) None case next(&self&.super) Just(newit) self <&.inner= newit into-iter() # we can do `next(self)` here, but recursive functions don't work. None return None fn flatten (it) it = it into-iter() case next(&it) Just(inner) return FlattenIter { super: it, inner: inner into-iter(), empty: False } # should handle empty iterators! None return FlattenIter { super: it, inner: @undefined, empty: True } # all permutations! fn permutations (lit, rit): lit map(fn x: rit map(fn y: (x, y))) flatten() fn cartesian (lit, rit): permutations(lit, rit) # previous name # comically inefficient TakeWhile it a it it pred a -> Bool inst IntoIter TakeWhile into-iter(self): self inst Iter TakeWhile next (self) mx = (&self&.it) next() case mx None return None Just(x) if self&.pred(x) return Just(x) else return None fn take-while(it, pred): TakeWhile { it: it into-iter(), pred } # drop while DropWhile it a it it pred a -> Bool finished Bool inst IntoIter DropWhile into-iter (self): self inst Iter DropWhile next (self) if self&.finished return (&self&.it) next() while True case (&self&.it) next() None self <&.finished= True return None Just(x) if not self&.pred(x) self <&.finished= True return Just(x) fn drop-while (it, pred): DropWhile { it: it into-iter(), pred, finished: False } # Haskell's `break`. fn break' (it, pred): Tuple2(it take-while(pred), it drop-while(pred)) fn combinations(it): it zip(from(1)) map(fn Tuple2(e, d): it drop(Mem.i32-size(d)) map(fn e': Tuple2(e, e'))) # TODO(safe-conversion) flatten() fn unordered-pairs(it): combinations(it) # previous name. ### append AppendIter e it it it elem e appended Bool fn append(it, e): AppendIter { it: it into-iter(), elem: e, appended: False } # reverse cons to nicely compose with postfix calling fn cons(it, e): append(it, e) # synonim for funi fn single(e): nil() cons(e) inst IntoIter AppendIter into-iter (self): self inst Iter AppendIter next (self) case (&self&.it) next() Just(x) return Just(x) None if not self&.appended self <&.appended= True return Just(self&.elem) return None FunIter a fun () -> Maybe a finished Bool inst IntoIter FunIter into-iter (self _): self inst Iter FunIter next (self Ptr _) if self&.finished return None case self&.fun() Just(x) return Just(x) None self <&.finished= True return None fn from-function (fun): FunIter { fun, finished: False } # SepBy! SepByNextIter a NextSep NextElem a SepByIter a it all-it it sep a next-it-type (SepByNextIter a) inst Iter SepByIter next (p Ptr _) -> Maybe item case p&.next-it-type NextSep case next(&p&.all-it) None return None Just(next-elem) p <&.next-it-type= NextElem(next-elem) return Just(p&.sep) NextElem(next-elem) next-elem = next-elem # this shouldn't be necessary and I should test for that. # (basically, what is the correct way to handle pointers from deconstructions n shi?) # it "makes sense", but it's a total footgun. p <&.next-it-type= NextSep return Just(next-elem) inst IntoIter SepByIter into-iter (self _): self fn sep-by (it, sep) all-it =& it into-iter() next-it-type = @undefined case all-it next() None next-it-type <= NextSep Just(x) next-it-type <= NextElem(x) return SepByIter { all-it: all-it&, sep, next-it-type } CycleIter it og it cur it inst IntoIter CycleIter into-iter (self): self inst Iter CycleIter next (self Ptr _) case next(&self&.cur) Just (x) return Just(x) None self <&.cur= self&.og return next(&self&.cur) fn cycle (it IntoIter) it = it into-iter() return CycleIter { og: it, cur: it } # consoomers fn for-each (iterable, fun) it =& into-iter(iterable) while True case next(it) None return Just(x) _ = fun(x) BreakForEach Continue Break fn for-each-break (iterable, fun) it =& into-iter(iterable) while True case next(it) None return Just(x) res = fun(x) case res Continue pass Break return fn reduce (iterable it, base a, fun (item, a) -> a) -> a <= IntoIter it x = base it = into-iter(iterable) while True case next(&it) None return x Just(res) x <= fun(res, x) @panic('unreachable') return @undefined # unreachable. we need better return checking. fn count(it it) -> Size <= IntoIter it: it reduce(0, fn (_, x): x + 1) fn sum(it): it reduce(0, fn (v, s): v + s) fn product(it): it reduce(1, fn (v, s): v * s) # design: maybe make them argument-less and just map() before using. # todo: eager exit # (after we make a `for` statement.) fn all(it, fun): it reduce(True, fn (e, x): fun(e) and x) # todo: eager exit fn any(it, fun): it reduce(False, fn (e, x): fun(e) or x) fn head(it): (&it into-iter()) next() fn last(it): it reduce(None, fn(e, _): Just(e)) fn null(it) case it head() None return True _ return False fn one-of(x, it): it any(fn e: e == x) inst ListDecon Range deconstruct (Range(rf, rt), lp, lc Size, spread, rp, rc Size) count = Mem.i32-size(rt - rf) fn set-ptr (p, i, e) pp = Mem.offset-ptr(p, i) pp <&= e if lc > 0 if lc > count return False Range(rf, rt) take(lc) zip(from(0)) for-each(fn Tuple2(lv, i): set-ptr(lp&, Mem.i32-i64(i), lv)) if rc > 0 if rc + lc > count return False Range(rf, rt) drop(count - rc + 1) zip(from(0)) for-each(fn Tuple2(rv, i): set-ptr(rp&, Mem.i32-i64(i), rv)) case spread NoSpread return lc + rc == count UnassignedSpread return True AssignedSpread(xptr) xptr <&= Range(rf + Mem.size-i32(lc), rt - Mem.size-i32(rc)) return True # Effectful versions # Sometimes, I just want to consoooooom # effectful version will end with a `'` fn drop'(it, n) 1 to (Mem.size-i32(n)) for-each(fn _: it next()) fn drop-while'(it iter, pred) -> iter <= Iter iter # not into-iter()-ing on purpose - this modifies the iterator directly, so we should operate only on actual iterators. it-copy = it while True case next(&it) None return it-copy Just(x) if not pred(x) return it-copy it-copy <= it # loops due to this return @undefined # This is unholy fn take-while'(it iter, pred) <= Iter iter, IntoIter iter # not into-iter()-ing on purpose - this modifies the iterator directly, so we should operate only on actual iterators. og = it took = 0 it-copy = it while True case next(&it) None return Tuple2(it-copy, og take(took)) Just(x) if not pred(x) return Tuple2(it-copy, og take(took)) took <= took + 1 it-copy <= it # loops due to this return @undefined # fn split'(it, pred) # clone-it = it& # tit = (&clone-it) take-while(pred) # drop-num = tit count() # dit = it drop'() #######