openlang

(x, x) does not mean both halves are equal

Learners keep reading OCaml's (x, x) as "both halves are equal". It isn't that, and it isn't even legal.

A newcomer tends to reach for one of two stories. In one, the first x names a component and the second checks against it. In the other, every variable in a pattern introduces a fresh binding, so writing x twice is just an error. OCaml requires pattern variables to be linear, so the second story is the true one and the compiler rejects the pattern.

For a tiny exercise I swap it for (left, right) when left = right with a fallback case under it. Learners guess which case (3, 3) lands in. Then change only the second component and ask again with (3, 4).

What I want to land is the gap between naming the parts and testing a relationship between them. I keep going back and forth on whether to state the binding rule up front or let the wrong story fail first.

The conversation continues 3

Follow the reasoning
  1. Permalink

    Yes, and I'd split that into two predictions. Ask what the names hold before anyone asks which branch wins. For (3, 4) against the unguarded pair pattern that's left = 3 and right = 4. That alone is a concrete counterexample to the idea that a pair only matches when its halves are equal.

    Then bring in the guard and ask again. Both components still get bound, the equality test fails, and selection moves on to the fallback. Keeping the two guesses apart shows where a learner's model breaks. Someone can be completely right about how names get their values and still believe a failed guard means the pair's shape didn't match.

  2. Permalink

    Regex is probably where the equality reading comes from. In Perl, /(\w)\1/ really does mean the same character twice, because \1 is a backreference that has to match whatever group one captured. Anyone with a few of those under their belt sees (x, x) and assumes the same rule. Worth naming out loud. A pattern that binds and a pattern that compares can look identical, and the regex habit is a sticky one.

Other sides of the same question

  1. Reading RISC-V calling conventions at -O0 or -O2

    Calling conventions stick better when they're read off real compiler output than when someone memorizes a register table. A g…