diff --git a/monoid-design.md b/monoid-design.md index e1d301952cf697651b005654d72c1c743c87e7c6..abfdbf8dca665798079ece965c84dd5a0152d072 100644 --- a/monoid-design.md +++ b/monoid-design.md @@ -236,14 +236,14 @@ If we ask for a total *and* a count, deferring the division, then we can find a Problem: Given a string of parentheses, determine if the parentheses are balanced. * Example of balanced parentheses: `()(())` -* Example of unbalanced parentheses: `…` -* Example of unbalanced parentheses with same number of each type: `…` +* Example of unbalanced parentheses: `((())` +* Example of unbalanced parentheses with same number of each type: `)(` ## Clues about the Monoid from an Iterative Design ```js function isBalanced(parentheses) { - let nesting = 0; + let nesting = 0; // ← result variable; related to the monoid (𝐙, +, 0) for (const character of parentheses) { if (character === '(') { ++nesting; @@ -262,40 +262,41 @@ function isBalanced(parentheses) { * Taking the submonoid generated by `(`: * The identity is different than `(`, which is different than `((`, which is different than `(((`, etc. - * So it seems like our monoid will need …. + * So it seems like our monoid will need a count of open parentheses, a factor like (𝐍, +, 0). * Taking the submonoid generated by `)`: * The identity is different than `)`, which is different than `))`, which is different than `)))`, etc. - * So it seems like our monoid will need …. + * So it seems like our monoid will need a count of close parentheses, a factor like (𝐍, +, 0). ## Quotienting a Free Monoid by Relations -* The sequence `…` cancels to the identity. -* If we simplify any input by repeatedly removing occurrences of `()`, we eventually end up with a string of the form …. +* The sequence `()` cancels to the identity. +* If we simplify any input by repeatedly removing occurrences of `()`, we eventually end up with a string of the form `)*(*` where `*` is the **Kleene star**. ## Parentheses Monoid * Monoid: - * `P = (…, ∙, …)` where `(a, b) ∙ (c, d) = (…, …)` + * `P = (𝐍×𝐍, ∙, (0, 0))` where `(a, b) ∙ (c, d) = (a + c - min(b, c), b + d - min(b, c))` + * (In `(a, b)`, `a` is the number of *unmatched* close parentheses, and `b` is the number of *unmatched* open parentheses.) ## Divide-and-Conquer Design ``` In: '()(())' - Out: + Out: 0, 0 / \ / \ / \ In: '()(' In: '())' - Out: Out: + Out: 0, 1 Out: 1, 0 / \ / \ / \ / \ In: '(' In: ')(' In: '(' In: '))' - Out: Out: Out: Out: + Out: 0, 1 Out: 1, 1 Out: 0, 1 Out: 2, 0 / \ / \ / \ / \ In: ')' In: '(' In: ')' In: ')' - Out: Out: Out: Out: + Out: 1, 0 Out: 0, 1 Out: 1, 0 Out: 1, 0 ``` ## New Iterative Solution @@ -303,22 +304,22 @@ function isBalanced(parentheses) { ```js function encode(character) { if (character === '(') { - return […, …]; + return [0, 1]; } if (character === ')') { - return […, …]; + return [1, 0]; } return [0, 0]; } function combine([leftCloses, leftOpens], [rightCloses, rightOpens]) { - const cancellations = …; - return […, …]; + const cancellations = Math.min(leftOpens, rightCloses); + return [leftCloses + rightCloses - cancellations, leftOpens + rightOpens - cancellations]; } function iterativeReduce(parentheses) { - let result = …; - for (const element of …) { + let result = [0, 0]; + for (const element of [...parentheses].map(encode)) { result = combine(result, element); } return result; @@ -337,7 +338,7 @@ async function parallelReduce(parentheses, threadCount) { jobs.push(job); } const [closes, opens] = iterativeReduce(await Promise.all(jobs)); - return …; + return closes === 0 && opens === 0; } ```