|
4 | 4 | <meta charset="UTF-8"> |
5 | 5 | <title>Kolibri Sequence Cheat Sheet</title> |
6 | 6 | <link rel="shortcut icon" type="image/png" href="../../../img/logo/logo-60x54.png"/> |
| 7 | + <link rel="stylesheet" href="../../../css/kolibri-base.css"> |
7 | 8 | </head> |
8 | 9 | <style> |
9 | 10 | body { |
10 | | - margin: 1em; |
| 11 | + margin-inline: 3rem; |
11 | 12 | } |
12 | | - main { |
13 | | - display: grid; |
14 | | - grid-template-columns: max-content max-content auto; |
15 | | - gap: .5lh 1em; |
| 13 | + |
| 14 | + header { |
| 15 | + margin-bottom: 2lh; |
16 | 16 | } |
17 | | - main div { |
18 | | - display: grid; |
19 | | - grid-template-columns: subgrid; |
20 | | - grid-column: 1 / -1; |
21 | | - align-items: baseline; |
| 17 | + |
| 18 | + .intro { |
| 19 | + padding: 1em; |
| 20 | + column-count: auto; |
| 21 | + column-width: 40ch; |
| 22 | + border-radius: .5em; |
| 23 | + color: black; |
| 24 | + box-shadow: var(--kolibri-box-shadow); |
| 25 | + |
| 26 | + & li { |
| 27 | + margin-bottom: .3lh; |
| 28 | + } |
| 29 | + |
| 30 | + & p:nth-child(1) { |
| 31 | + margin-top: 0; |
| 32 | + } |
22 | 33 | } |
23 | | - .src, .out { |
24 | | - font-family: monospace; |
| 34 | + |
| 35 | + |
| 36 | + main div { |
| 37 | + display: flex; |
| 38 | + flex-direction: column; |
| 39 | + gap: .5lh; |
| 40 | + padding: .8em; |
| 41 | + font-family: monospace; |
| 42 | + border-radius: 1em; |
| 43 | + &:nth-child(odd) { |
| 44 | + background-color: rgb( from var(--kolibri-color-shadow) r g b / .03); |
| 45 | + } |
25 | 46 | } |
| 47 | + |
26 | 48 | .src { |
27 | | - white-space: pre-line; |
| 49 | + white-space: pre; |
28 | 50 | } |
| 51 | + |
29 | 52 | .out { |
30 | | - color: #0006; |
| 53 | + color: var(--kolibri-color-output); |
| 54 | + opacity: 60%; |
| 55 | + word-wrap: break-word; |
31 | 56 | } |
32 | 57 |
|
33 | 58 | </style> |
34 | 59 | <body> |
35 | 60 | <header> |
36 | | - <h1>Kolibri Sequence Cheat Sheet</h1> |
| 61 | + <h1>Kolibri Sequence Cheat Sheet</h1> |
| 62 | + <div class="intro"> |
| 63 | + <p> |
| 64 | + The Kolibri Sequence facility is an extension of the standard |
| 65 | + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols">Iteration |
| 66 | + protocols</a> that are in the JavaScript stdlib since 2016 |
| 67 | + and have been upgraded considerably with Baseline 2025 that introduced |
| 68 | + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator">new |
| 69 | + Iterator functions</a> like map, filter, reduce, forEach, flatMap, and more. |
| 70 | + </p> |
| 71 | + <p> |
| 72 | + This cheat sheet shows how to use Kolibri Sequences and how they play nicely together |
| 73 | + with the stdlib iteration features. For full coverage, see the Kolibri sequence test cases and |
| 74 | + additional demos and examples. |
| 75 | + </p> |
| 76 | + <p> |
| 77 | + A few things to keep in mind that make all Kolibri Sequences and their operators special: |
| 78 | + </p> |
| 79 | + <ul> |
| 80 | + <li>all constructors and operators are thoroughly typed, documented, and tested</li> |
| 81 | + <li>Sequences are immutable, lazy, compositional, and pure (as long as the callback functions are pure)</li> |
| 82 | + <li>Sequences can be infinite</li> |
| 83 | + <li>names of operators that should only be called on finite sequences end with a $ character (e.g. |
| 84 | + reduce$) |
| 85 | + </li> |
| 86 | + <li>non-terminal operators can be chained (they are monoidal where possible)</li> |
| 87 | + <li>Sequences provide "fusion optimization" by design</li> |
| 88 | + <li>all operators are available as instance methods as well as utility functions in curried |
| 89 | + style for eta reduction, pipelining, and custom operators |
| 90 | + </li> |
| 91 | + <li>Sequences - along with Pair, Tuple, MayBe, and JSON - are monadic and can therefore be used |
| 92 | + with JINQ like in from(...).where(...).select(...).result() |
| 93 | + </li> |
| 94 | + </ul> |
| 95 | + </div> |
37 | 96 | </header> |
38 | 97 |
|
39 | 98 | <main> |
@@ -62,86 +121,85 @@ <h1>Kolibri Sequence Cheat Sheet</h1> |
62 | 121 | </div> |
63 | 122 | `); |
64 | 123 | const codeLines = [ |
65 | | - "Walk().show()", |
66 | | - "Walk().show(10)", |
67 | | - "Walk(5).show()", |
68 | | - "Walk(5,10).show()", |
69 | | - "Walk(0,20,5).show()", |
70 | | - "Walk(100,0,-7).show()", |
71 | | - "Walk(1,ALL,2).take(4).show()", |
72 | | - "Walk(1,5,2) ['=='] (Walk(5,1,2))", |
73 | | - "Walk(1,5,-2).eq$(Walk(5,1,-2))", |
74 | | - "Seq().show()", |
75 | | - "Seq(1,2,3).show()", |
76 | | - "Seq(3,4,5,6) ['=='] (Walk(3,6))", |
77 | | - "Seq(42,'***',true).show()", |
78 | | - "Seq(...[1,2,3]).eq$(Walk(1,3))", |
79 | | - "Seq(1).cycle().show()", |
80 | | - "Seq(1).cycle().show()", |
81 | | - "Seq('_','🌹').cycle().show()", |
82 | | - "Sequence('a', x => x.length < 100, x => x+x).show()", |
83 | | - "Sequence(1, forever, x => x/2).show()", |
84 | | - "Walk().map (n => n*n).show()", |
85 | | - "Walk().fmap(n => n*n).show()", |
86 | | - "Walk().take(5).show()", |
87 | | - "Walk().takeWhile(n => n < 9).show()", |
88 | | - "Walk().takeWhere(n => n % 3 === 0).show()", |
89 | | - "Walk().drop(5).show()", |
90 | | - "Walk().dropWhile(n => n < 9).show()", |
91 | | - "Walk().dropWhere(n => n % 3 === 0).show()", |
92 | | - "Walk(1,5).count$()", |
93 | | - "Walk(1,5).reduce$( (acc,cur) => acc + cur, 0)", |
94 | | - "Walk(1,5).reduce$(plusOp, 0)", |
95 | | - "Walk(1,5).map(String).foldl$(plusOp, '')", |
96 | | - "Walk(1,5).map(String).scan(plusOp, '').show()", |
97 | | - "Seq(1,2,3).append(Walk()).show()", |
98 | | - "Seq(1,2,3) ['++'] (Walk()).show()", |
99 | | - "Seq(1,2,3).cons(0).show()", |
100 | | - "Seq(1,2,3).snoc(4).show()", |
101 | | - "Walk(1,4).and( n => Walk(1,n)).show()", |
102 | | - "Walk().and( n => n < 10 ? Seq() : Seq(n,n)).show()", |
103 | | - "Seq(Just(1), Nothing, Just(2)).catMaybes().show()", |
104 | | - `const getAt = idx => Seq(drop(idx-1), take(1)); |
105 | | - Walk().pipe(...getAt(10)).show()`, |
106 | | - "Seq(...Pair(1)(2)).show()", |
107 | | - `const [Triple] = Tuple(3); |
108 | | - TupleSequence(Triple ('_')(42)(true) ).show()`, |
109 | | - "Seq(1,2,3).reverse$().show()", |
110 | | - "Seq(1,2,3).min$()", |
111 | | - "Seq('**','***','*').max$((a,b) => a.length < b.length)", |
112 | | - `const seen = []; |
113 | | - Walk() |
114 | | - .tap(n=>seen.push(n)) |
115 | | - .take(5) |
116 | | - .forEach$(id); |
117 | | - seen;`, |
118 | | - `const seen = []; |
119 | | - for(const x of Walk().take(5)) { seen.push(x) } |
120 | | - seen;`, |
121 | | - "[...Walk().take(5)]", |
122 | | - "[...Iterator.from(Walk()).take(5)] // Seq -> JS Iterator", |
123 | | - `const every = f => reduce$((acc,cur) => acc && f(cur),true); |
124 | | - Walk(10).pipe(every(n=> n < 11));`, |
125 | | - `const some = f => seq => ! seq.takeWhere(f).isEmpty(); |
126 | | - Walk().pipe(some(n=> n > 10));`, |
127 | | - `const last = reduce$((_acc,cur) => Just(cur), Nothing); |
128 | | - Walk(10).pipe(last)(_=>"no last value")(id);`, |
129 | | - `const last = reduce$((_acc,cur) => Just(cur), Nothing); |
130 | | - Seq().pipe(last)(_=>"no last value")(id);`, |
131 | | - `Seq('*','**','***').zip(Walk()).map(([n,i]) => i+":"+n).show()`, |
132 | | - `Seq('*','**','***').zipWith((n,i) => i+":"+n)(Walk()).show()`, |
133 | | - `// make sequence from iterable without consuming |
134 | | - toSeq("abc").show();`, |
135 | | - `toSeq("hello kolibri".split(/ /)).show();`, |
136 | | - `toSeq("0+1-2+3-44".match(/-\\d*/g)).show();`, |
137 | | - `toSeq(document.querySelectorAll('.src')).count$();`, |
138 | | - `toSeq(document.body.children).count$();`, |
139 | | - `from( Walk(2,ALL)) |
140 | | - .combine( z => Walk(2,z,1)) |
141 | | - .combine( ([z,y]) => Walk(2,Math.sqrt(z),1)) |
142 | | - .where ( ([[z,y], x]) => x * y === z ) |
143 | | - .select ( ([[z,y], x]) => z+"="+y+"*"+x) |
144 | | - .result().show();`, |
| 124 | +"Walk().show()", |
| 125 | +"Walk().show(10)", |
| 126 | +"Walk(5).show()", |
| 127 | +"Walk(5,10).show()", |
| 128 | +"Walk(0,20,5).show()", |
| 129 | +"Walk(100,0,-7).show()", |
| 130 | +"Walk(1,ALL,2).take(4).show()", |
| 131 | +"Walk(1,5,2) ['=='] (Walk(5,1,2))", |
| 132 | +"Walk(1,5,-2).eq$(Walk(5,1,-2))", |
| 133 | +"Seq().show()", |
| 134 | +"Seq(1,2,3).show()", |
| 135 | +"Seq(3,4,5,6) ['=='] (Walk(3,6))", |
| 136 | +"Seq(42,'***',true).show()", |
| 137 | +"Seq(...[1,2,3]).eq$(Walk(1,3))", |
| 138 | +"Seq(1).cycle().show()", |
| 139 | +"Seq('_','🌹').cycle().show()", |
| 140 | +"Sequence('a', x => x.length < 100, x => x+x).show()", |
| 141 | +"Sequence(1, forever, x => x+x).show(17)", |
| 142 | +"Walk().map (n => n*n).show()", |
| 143 | +"Walk().fmap(n => n*n).show()", |
| 144 | +"Walk().take(5).show()", |
| 145 | +"Walk().takeWhile(n => n < 9).show()", |
| 146 | +"Walk().takeWhere(n => n % 3 === 0).show()", |
| 147 | +"Walk().drop(5).show()", |
| 148 | +"Walk().dropWhile(n => n < 9).show()", |
| 149 | +"Walk().dropWhere(n => n % 3 === 0).show()", |
| 150 | +"Walk(1,5).count$()", |
| 151 | +"Walk(1,5).reduce$( (acc,cur) => acc + cur, 0)", |
| 152 | +"Walk(1,5).reduce$(plusOp, 0)", |
| 153 | +"Walk(1,5).map(String).foldl$(plusOp, '')", |
| 154 | +"Walk(1,5).map(String).scan(plusOp, '').show()", |
| 155 | +"Seq(1,2,3).append(Walk()).show()", |
| 156 | +"Seq(1,2,3) ['++'] (Walk()).show()", |
| 157 | +"Seq(1,2,3).cons(0).show()", |
| 158 | +"Seq(1,2,3).snoc(4).show()", |
| 159 | +"Walk(1,4).and( n => Walk(1,n)).show()", |
| 160 | +"Walk().and( n => n < 10 ? Seq() : Seq(n,n)).show()", |
| 161 | +"Seq(Just(1), Nothing, Just(2)).catMaybes().show()", |
| 162 | +`const getAt = idx => Seq(drop(idx-1), take(1)); |
| 163 | +Walk().pipe(...getAt(10)).show()`, |
| 164 | +"Seq(...Pair(1)(2)).show()", |
| 165 | +`const [Triple] = Tuple(3); |
| 166 | +TupleSequence(Triple ('_')(42)(true) ).show()`, |
| 167 | +"Seq(1,2,3).reverse$().show()", |
| 168 | +"Seq(1,2,3).min$()", |
| 169 | +"Seq('**','***','*').max$((a,b) => a.length < b.length)", |
| 170 | +`const seen = []; |
| 171 | +Walk() |
| 172 | +.tap(n=>seen.push(n)) // keep side effects in "tap" |
| 173 | +.take(5) |
| 174 | +.forEach$(id); |
| 175 | +seen;`, |
| 176 | +`const seen = []; |
| 177 | +for(const x of Walk().take(5)) { seen.push(x) } |
| 178 | +seen;`, |
| 179 | +"[...Walk().take(5)]", |
| 180 | +"Iterator.from(Walk()).take(5).toArray() // Seq -> JS Iterator", |
| 181 | +`const every = f => reduce$((acc,cur) => acc && f(cur),true); |
| 182 | +Walk(10).pipe(every(n=> n < 11));`, |
| 183 | +`const some = f => seq => ! seq.takeWhere(f).isEmpty(); |
| 184 | +Walk().pipe(some(n=> n > 10));`, |
| 185 | +`const last = reduce$((_acc,cur) => Just(cur), Nothing); |
| 186 | +Walk(10).pipe(last)(_=>"no last value")(id);`, |
| 187 | +`const last = reduce$((_acc,cur) => Just(cur), Nothing); |
| 188 | +Seq().pipe(last)(_=>"no last value")(id);`, |
| 189 | +`Seq('*','**','***').zip(Walk()).map(([n,i]) => i+":"+n).show()`, |
| 190 | +`Seq('*','**','***').zipWith((n,i) => i+":"+n)(Walk()).show()`, |
| 191 | +`// make sequence from iterable without consuming |
| 192 | +toSeq("abc").show();`, |
| 193 | +`toSeq("hello kolibri".split(/ /)).show();`, |
| 194 | +`toSeq("0+1-2+3-44".match(/-\\d*/g)).show();`, |
| 195 | +`toSeq(document.querySelectorAll('.src')).count$();`, |
| 196 | +`toSeq(document.body.children).count$();`, |
| 197 | +`from( Walk(2,ALL)) |
| 198 | +.combine( z => Walk(2,z,1)) |
| 199 | +.combine( ([z,y]) => Walk(2,Math.sqrt(z),1)) |
| 200 | +.where ( ([[z,y], x]) => z === y * x ) |
| 201 | +.select ( ([[z,y], x]) => z + "=" + y + "*" + x) |
| 202 | +.result().show();`, |
145 | 203 | ]; |
146 | 204 | codeLines.forEach( line => main.append(...makeRow(line, eval(line))) ); |
147 | 205 |
|
|
0 commit comments