openlang

(x, x) не значит, что обе половины равны

Ученики раз за разом читают (x, x) в OCaml как «обе половины равны». Это не так, и такой паттерн вообще недопустим.

Новичок обычно хватается за одно из двух объяснений. В первом x сначала даёт имя компоненту, а второе вхождение сравнивается с ним. Во втором каждая переменная в паттерне вводит новую привязку, так что повтор x просто даёт ошибку. OCaml требует, чтобы переменные в паттерне были линейными, поэтому верно второе, и компилятор такой паттерн отвергает.

Для маленького упражнения я заменяю его на (left, right) when left = right с запасной веткой ниже. Пусть ученики угадают, в какую ветку попадёт (3, 3). Потом меняем только второй компонент и спрашиваем снова про (3, 4).

Донести хочется разницу между тем, чтобы назвать части, и тем, чтобы проверить отношение между ними. До сих пор колеблюсь, назвать правило о привязках сразу или дать неверному объяснению сначала развалиться.

Разговор продолжается 3

Следуя доводам
  1. Ссылка на ответ

    Тогда на шаг раньше. Пусть (3, 4) сначала сопоставится с простым (left, right) без всякого условия, чтобы было видно, как значения привязываются. Охранное условие на равенство добавим уже потом.

  2. Ссылка на ответ

    Да, и тут лучше два отдельных предсказания. Сначала спросить, что лежит в именах, и только потом, какая ветка выигрывает. Для (3, 4) и паттерна пары без условия получаем left = 3 и right = 4. Уже одно это служит конкретным контрпримером к мысли, что пара сопоставляется, только когда половины равны.

    Потом вводим условие и спрашиваем снова. Оба компонента всё так же привязываются, проверка равенства не проходит, и выбор переходит к запасной ветке. Если держать две догадки отдельно, видно, где именно ломается представление ученика. Можно совершенно верно понимать, как имена получают значения, и всё равно считать, что проваленное условие означает несовпадение формы пары.

  3. Ссылка на ответ

    Скорее всего, привычка читать это как равенство приходит из регулярных выражений. В Perl /(\w)\1/ действительно значит один и тот же символ дважды, потому что \1 это обратная ссылка, которая должна совпасть с тем, что захватила первая группа. Кто написал несколько таких, видит (x, x) и ждёт того же правила. Это стоит проговорить вслух. Шаблон, который связывает, и шаблон, который сравнивает, могут выглядеть одинаково, а привычка от регулярок очень цепкая.

Другие стороны того же вопроса

  1. Соглашения о вызовах RISC-V по выводу -O0 или -O2

    Соглашения о вызовах запоминаются лучше, когда их вычитывают из настоящего вывода компилятора, а не заучивают по таблице реги…

    Ответы 3assemblyc