|
| 1 | +{# This file is part of DBL, released under the MIT license. |
| 2 | + # See LICENSE for details. |
| 3 | + #} |
| 4 | + |
| 5 | +import open /Lazy |
| 6 | + |
| 7 | +## # Stream module |
| 8 | + |
| 9 | +{## |
| 10 | + This module provides lazy lists, also known as streams. |
| 11 | + Each and every node of a stream is deferred, meaning that |
| 12 | + no computation occurs unless results are forcibly read. |
| 13 | + |
| 14 | + Contrary to regular lists, streams may be infinite. Some iterative |
| 15 | + functions may never terminate! |
| 16 | + ##} |
| 17 | + |
| 18 | +rec |
| 19 | + ## Stream type. |
| 20 | + abstr data Stream X = Stream of Lazy (Node X) |
| 21 | + data Node X = |
| 22 | + | Cons of X, Stream X |
| 23 | + | Nil |
| 24 | +end |
| 25 | + |
| 26 | +parameter X : type |
| 27 | + |
| 28 | +method unstream (Stream xs) = xs |
| 29 | + |
| 30 | +{## Creates stream from given list. ##} |
| 31 | +pub let rec fromList (xs : List X) = |
| 32 | + Stream (lazy (fn _ => |
| 33 | + match xs with |
| 34 | + | [] => Nil |
| 35 | + | x :: xs => Cons x (fromList xs) |
| 36 | + end)) : Stream X |
| 37 | + |
| 38 | +{## Returns all elements of a stream as a list. ##} |
| 39 | +pub let rec toList (Stream xs : Stream X) = |
| 40 | + match xs.force with |
| 41 | + | Nil => [] : List X |
| 42 | + | Cons x xs => x :: toList xs |
| 43 | + end : List X |
| 44 | + |
| 45 | +{## |
| 46 | + Initializes lazy stream by iteratively applying function `f` on previous results. |
| 47 | + |
| 48 | + This function may generate infinite stream. |
| 49 | + ##} |
| 50 | +pub let rec unfold {S} (seed : S) (f : S ->[] Option (Pair X S)) = |
| 51 | + Stream (lazy (fn _ => |
| 52 | + match f seed with |
| 53 | + | None => Nil |
| 54 | + | Some (val, seed) => Cons val (unfold seed f) |
| 55 | + end)) : Stream X |
| 56 | + |
| 57 | +{## Creates an empty stream. ##} |
| 58 | +pub let empty = (Stream (pureLazy Nil) : Stream X) |
| 59 | + |
| 60 | +{## Checks if a stream is empty. ##} |
| 61 | +pub let isEmpty (Stream xs : Stream X) = |
| 62 | + match xs.force with |
| 63 | + | Nil => True |
| 64 | + | _ => False |
| 65 | + end |
| 66 | + |
| 67 | +{## Creates a stream from given element. ##} |
| 68 | +pub let singleton (elem : X) = |
| 69 | + Stream (pureLazy (Cons elem empty)) |
| 70 | + |
| 71 | +{## Adds an element to the head of a stream. ##} |
| 72 | +pub let cons (elem : X) (tail : Stream X) = |
| 73 | + Stream (pureLazy (Cons elem tail)) |
| 74 | + |
| 75 | +{## Adds a deferred element to the head of a stream. ##} |
| 76 | +pub let lazyCons (elem : Lazy X) (tail : Stream X) = |
| 77 | + Stream (lazy (fn _ => Cons elem.force tail)) |
| 78 | + |
| 79 | +{## |
| 80 | + Returns head and tail of a stream. |
| 81 | + Returns `None` if stream is empty. |
| 82 | + ##} |
| 83 | +pub let uncons (Stream xs : Stream X) = |
| 84 | + match xs.force with |
| 85 | + | Nil => None |
| 86 | + | Cons x xs => Some (x, xs) |
| 87 | + end |
| 88 | + |
| 89 | +{## |
| 90 | + Creates a new stream with mapped values. |
| 91 | + ##} |
| 92 | +pub let rec map {Y} (f : X ->> Y) (Stream xs : Stream X) = |
| 93 | + Stream (lazy (fn _ => |
| 94 | + match xs.force with |
| 95 | + | Nil => Nil |
| 96 | + | Cons x xs => Cons (f x) (map f xs) |
| 97 | + end)) : Stream Y |
| 98 | + |
| 99 | +{## Appends two streams together. ##} |
| 100 | +pub let rec append (Stream xs : Stream X) (ys : Stream X) = |
| 101 | + Stream (lazy (fn _ => |
| 102 | + match xs.force with |
| 103 | + | Nil => ys.unstream.force |
| 104 | + | Cons x xs => Cons x (append xs ys) |
| 105 | + end)) : Stream X |
| 106 | + |
| 107 | +{## Performs monadic bind over a stream. ##} |
| 108 | +pub let rec concatMap {Y} (f : X ->> Stream Y) (Stream xs : Stream X) = |
| 109 | + Stream (lazy (fn _ => |
| 110 | + match xs.force with |
| 111 | + | Nil => Nil |
| 112 | + | Cons x xs => append (f x) (concatMap f xs) >.unstream >.force |
| 113 | + end)) : Stream Y |
| 114 | + |
| 115 | +{## |
| 116 | + Returns the longest prefix of a stream that satisfies the given predicate. |
| 117 | + ##} |
| 118 | +pub let rec takeWhile (f : X ->> Bool) (Stream xs : Stream X) = |
| 119 | + Stream (lazy (fn _ => |
| 120 | + match xs.force with |
| 121 | + | Nil => Nil |
| 122 | + | Cons x xs => |
| 123 | + if f x then |
| 124 | + Cons x (takeWhile f xs) |
| 125 | + else |
| 126 | + Nil |
| 127 | + end)) : Stream X |
| 128 | + |
| 129 | +{## Returns a substream with values that satisfy the given predicate. ##} |
| 130 | +pub let rec filter (f : X ->> Bool) (Stream xs : Stream X) = |
| 131 | + Stream (lazy (fn _ => |
| 132 | + match xs.force with |
| 133 | + | Nil => Nil |
| 134 | + | Cons x xs => |
| 135 | + if f x then |
| 136 | + Cons x (filter f xs) |
| 137 | + else |
| 138 | + filter f xs >.unstream >.force |
| 139 | + end)) : Stream X |
| 140 | + |
| 141 | +{## |
| 142 | + Folds stream to a single value, beginning with right-most value. |
| 143 | + ##} |
| 144 | +pub let rec foldRight {A} |
| 145 | + (f : X -> A ->> A) (Stream xs : Stream X) (acc : A) = |
| 146 | + match xs.force with |
| 147 | + | Nil => acc |
| 148 | + | Cons x xs => f x (foldRight f xs acc) |
| 149 | + end : A |
| 150 | + |
| 151 | +{## |
| 152 | + Folds stream to a single value from right to left. Takes the last |
| 153 | + element of a stream as an initial accumulator. |
| 154 | + Calls `~onError` in case of an empty stream. |
| 155 | + |
| 156 | + @param ~onError Fallback for an empty stream. |
| 157 | + ##} |
| 158 | +pub let foldRight1Err {~onError : Unit ->> X} |
| 159 | + (f : X -> X ->> X) (Stream xs : Stream X) = |
| 160 | + let rec foldRight1ErrAux y (Stream xs) = |
| 161 | + match xs.force with |
| 162 | + | Nil => y |
| 163 | + | Cons x xs => |
| 164 | + f y (foldRight1ErrAux x xs) |
| 165 | + end |
| 166 | + in |
| 167 | + match xs.force with |
| 168 | + | Nil => ~onError () |
| 169 | + | Cons x xs => foldRight1ErrAux x xs |
| 170 | + end : X |
| 171 | + |
| 172 | +{## Checks if all elements of given streams are equal pairwise. ##} |
| 173 | +pub let equal |
| 174 | + {method equal : X -> X ->[] Bool} |
| 175 | + (xs : Stream X) |
| 176 | + (ys : Stream X) = |
| 177 | + let rec equalAux ((Stream xs) : Stream X) ((Stream ys) : Stream X) = |
| 178 | + match (xs.force, ys.force) with |
| 179 | + | Nil, Nil => True |
| 180 | + | Cons x xs, Cons y ys => |
| 181 | + if x == y then |
| 182 | + equalAux (xs : Stream X) ys |
| 183 | + else |
| 184 | + False |
| 185 | + | _ => False |
| 186 | + end |
| 187 | + in |
| 188 | + equalAux xs ys |
| 189 | + |
| 190 | +{## Enables stream showing in REPL. ##} |
| 191 | +pub let show (_ : Stream X) = "#Stream" |
| 192 | + |
| 193 | +parameter ~onError |
| 194 | + |
| 195 | +pub method toList = toList |
| 196 | +pub method uncons = uncons |
| 197 | +pub method map = flip map |
| 198 | +pub method add = append |
| 199 | +pub method concatMap = flip concatMap |
| 200 | +pub method filter = flip filter |
| 201 | +pub method foldRight xs f acc = foldRight f xs acc |
| 202 | +pub method foldRight1Err = flip foldRight1Err |
| 203 | +pub method equal = equal |
| 204 | +pub method show = show |
0 commit comments