8 comments

  • macintux7 hours ago
    One of the few lessons I distinctly remember from college was finite automata in my PL class. I really enjoyed exploring the concepts and writing a grep tool; we were supposed to write either a NFA or DFA processing application, but I decided to write both.<p>20 years later I got to apply some of the same ideas to a language processing application, and it was such a pleasure to actually use something conceptual like that. Made me briefly regret landing in more hybrid infrastructure&#x2F;automation roles instead of pure software development.<p>Somewhere I may still have my copy of Preperata and Yeh that my professor recommended at the time for further reading. Like most of my books, it was never actually read, just sat around for years.
  • userbinator3 hours ago
    <i>we’ll ask, “What’s the simplest possible computing machine that can recognize balanced parentheses?”</i><p>A counter. That&#x27;s the difference between theory and practice. Because in practice, everything is finite.
    • jibal1 hour ago
      The counter is simply the stack depth without bothering with the actual stack. If the stack is empty when you encounter a closer then it&#x27;s unbalanced. If the stack isn&#x27;t empty when you reach the end of the input then the items in the stack are unbalanced.<p>If you have multiple kinds of brackets then you need the same number of counters. Each counter corresponds to the number of openers of that type currently on the stack. EDIT: this is wrong. Counters can&#x27;t distinguish between [() and ([)<p>If you&#x27;re writing a parser and you want to report the location of an unclosed opening bracket then you need the actual stack.
      • spyrja35 minutes ago
        FWIW it&#x27;s a fairly straightforward algorithm. In C++:<p><pre><code> bool balanced(const string&amp; text, const string&amp; open, const string&amp; close) { size_t length = text.size(), brackets = open.size(); assert(close.size() == brackets); stack&lt;char&gt; buffer; for (size_t index = 0; index &lt; length; ++index) { char ch = text[index]; for (size_t slot = 0; slot &lt; brackets; ++slot) { if (ch == open[slot]) buffer.push(ch); else if (ch == close[slot]) { if (buffer.empty() || buffer.top() != open[slot]) return false; buffer.pop(); } } } return buffer.empty(); }</code></pre>
      • vidarh1 hour ago
        You need the actual stack, I think, in the case of multiple types of openers without additional constraints, because if you just have raw counters you&#x27;d get tripped up by ([)] or similar.<p>So to generalise your point you need a counter for each transition to a different type of opener.<p>So (([])) needs only 2 counters, not 3.<p>You could constrain it further if certain types of openers are only valid in certain cases so you could exclude certain types of transitions.<p>EDIT:<p>([)] could indeed be handled by just additionally tracking the <i>current</i> open type. (([]]) is a better example, as it shows that to handle deeper nesting you need additional pieces of data that will grow at some rate (at most by the number of opens, possibly lower depending on which types can validly appear within which types)
      • gpderetta1 hour ago
        Wouldn&#x27;t two counters report &quot;([)]&quot; as being properly balanced?
        • jibal57 minutes ago
          No, there&#x27;s an open [ when the ) is encountered. The problem is the other way around -- my algorithm would report [() as an error. Oops, back to the drawing board. Clearly no counting can tell the difference between [() and ([).
    • nmadden3 hours ago
      &gt; Because in practice, everything is finite.<p>Indeed! <a href="https:&#x2F;&#x2F;neilmadden.blog&#x2F;2019&#x2F;02&#x2F;24&#x2F;why-you-really-can-parse-html-and-anything-else-with-regular-expressions&#x2F;" rel="nofollow">https:&#x2F;&#x2F;neilmadden.blog&#x2F;2019&#x2F;02&#x2F;24&#x2F;why-you-really-can-parse-...</a>
    • testaccount283 hours ago
      you don&#x27;t need a full counter. increment, decrement, and check_if_zero are enough. no need for get_value.
      • stellalo3 hours ago
        you also need check_if_negative to detect close-before-open
        • jibal2 hours ago
          The counter is at 0, which indicates an error ... that plus the counter being non-zero when reaching the end of input is the entire point.
    • pfortuny2 hours ago
      Yes. Actually, a more interesting example which does not complicate the statement (not the problem) too much is to check for nested parenthesis and brackets:<p>(([[()])) -&gt; ok ((([](])) -&gt; not ok<p>Hope OP gets this message.
      • _0ffh1 hour ago
        In case anybody is interested, when we generalize the concept we&#x27;re talking about Dyck languages.<p><a href="https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Dyck_language" rel="nofollow">https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Dyck_language</a>
        • reuben36442 minutes ago
          I was surprised to not see a connection made to free groups in the article.<p>EDIT: The wikipedia article that is.
      • jibal1 hour ago
        .
        • immibis1 hour ago
          Your solution incorrectly fails ({}). You need the stack.
          • jibal1 hour ago
            You&#x27;re right ... no counter can tell the difference between ({ and {(. Oops.
  • praptak2 hours ago
    <i>&quot;But on a day-to-day basis, if asked to recognize balanced parentheses?&quot;</i><p>On day-to-day basis you will never encounter this problem in pure form. As the consequence the solutions are not good for the day-to-day stuff.<p>Even if you only are only writting a verifier (which is already a bit unrealistic), you&#x27;ll need to say something more than &quot;not balanced&quot;. Probably rather something along the lines of &quot;closing brace without a matching opening at [position]&quot; or &quot;[n] unclosed parentheses at &lt;end of stream&gt;&quot; which rules out the simple recursive regex approach (counter still works).
    • jibal1 hour ago
      To report the location of an unclosed opener you need a stack.
      • vidarh1 hour ago
        Depends. You <i>want</i> a stack, as it&#x27;s certainly more efficient, but if you can rewind the position pointer you don&#x27;t <i>need</i> one (you can count backwards).<p>EDIT: It gets complicated if you need to count <i>multiple different types of openers</i>. In that case I think you <i>need</i> the stack, at least unless there are constraints on which openers can occur within others - you at the very least need to know which closer you&#x27;re looking for right now, but if you can&#x27;t deduce what is outside, you obviously then need to keep track of it.<p>In practice, of course, we&#x27;ll generally use a stack because it&#x27;s just pointless to make life harder by not using one for this.
        • jibal1 hour ago
          If you&#x27;ve encountered 1 million unclosed parentheses, any or all of them could be unbalanced, so to report which ones are, you need 1 million pieces of information. The obvious way to organize them is as stack. Of course there are <i>worse</i> ways to do it. Rewinding the position pointer means that you&#x27;ve kept the entire input as a stack of characters, and now you have to keep track of all the closers on a stack in order to balance them with their openers.<p>You NEED a stack.<p>(And no, I didn&#x27;t presume anything ... I addressed rewinding above.)
          • vidarh1 hour ago
            You&#x27;re presuming you have only a non-rewindable stream as opposed to a file interface, which is why I was explicit about the requirement to be able to rewind the position to avoid a stack. If you only have a non-rewindable stream, then, yes, you need a strack. If you have a file handle, you do not.<p>(and yes, you did presume something; if you have rewindable file handle, you do not need to keep the characters; you can instead-re-read them)
  • senorqa4 hours ago
    The pictures of Brutalist architecture are awesome!
  • firechickenbird2 hours ago
    The proof of non-regularity is a bit convoluted. You can easily apply the pumping lemma there
  • Antibabelic3 hours ago
    What is some further reading y&#x27;all could recommend on formal languages?
    • praptak2 hours ago
      That&#x27;s what I learnt from as part of CS curriculum at MiMUW. Can recommend: <a href="https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Introduction_to_Automata_Theory,_Languages,_and_Computation" rel="nofollow">https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Introduction_to_Automata_Theor...</a>
    • tehnub3 hours ago
      sipser&#x27;s theory of computation
  • stefantalpalaru1 hour ago
    [dead]