Открытые и закрытые системы эффектов
— 2025-05-22Yoshua Wuyts Источник
Обсуждая системы эффектов в контексте производственных языков программирования, я считаю, что самое важное различие — это определены ли эффекты исключительно языком или пользователи также могут их определять. Когда Магнус Мадсен (Magnus Madsen) из языка программирования Flix присоединился к звонку Rust T-Lang на две сессии в прошлом декабре, он использовал термины «открытые» и «закрытые», чтобы описать это различие:
- Закрытые системы эффектов: это системы, в которых все эффекты определены языком как встроенные. Количество эффектов может со временем расти, но эффекты определяются только самим языком. Это делает количество возможных эффектов ограниченным.
- Открытые системы эффектов: позволяют пользователям языка также определять свои собственные эффекты управления потоком, которые существуют наряду со встроенными эффектами языка. Это делает количество возможных эффектов неограниченным.
Самые интересные эффекты в языках программирования должны быть встроенными. Сюда входят такие вещи, как контроль того, гарантирует ли функция своё завершение («расходимость»), или разрешено ли функции выполнять побочные эффекты («чистота»).
Это отличается от пользовательских эффектов. Обычно они определяются с помощью «обработчиков алгебраических эффектов», но я также встречал использование термина «типизированные продолжения»1. Я думаю о них более или менее как о поддержке на уровне языка для тщательно типизированных итераторов/генераторов/сопрограмм. Не имеет особого смысла выражать «расходимость» с помощью итераторов. Вот почему, хотя все обработчики эффектов являются эффектами, не все эффекты выражаются с помощью обработчиков эффектов.
В контексте Rust всё, что мы обсуждаем сейчас, — это введение закрытой системы эффектов. И это не потому, что мы считаем, что открытая система не была бы полезной или хорошей. А потому, что формализация и обобщение системы эффектов Rust обратно-совместимым образом сама по себе представляет собой невероятный объём работы. И чтобы выпустить её, мы должны где-то провести черту2.
Примечания
-
Я считаю, что между двумя терминами есть разница, но не совсем помню её. Однако я нахожу термин «типизированные продолжения» гораздо более выразительным. Выходец из Node.js 0.8, я думаю об этом примерно как о «что, если бы все обратные вызовы были полностью типизированы и у нас был компилятор, гарантирующий их обработку». Возможно, синтаксически не то же самое, но я думаю, что семантически это довольно близко. ← ↩
-
Хотя это не означает, что мы не можем оставить синтаксическое пространство открытым для рассмотрения этого позже. Тот факт, что мы говорим «не сейчас», не означает, что мы говорим «никогда». ← ↩