Какое хорошее объяснение принципа соответствия Теннента?

21

Мне было трудно понять, в чем заключается этот принцип и почему он так важен для языкового дизайна.

По сути, в нем говорится, что для каждого выражения exprв языке должно быть точно так же, как эта конструкция:

(function () { return expr; })()

Кроме того, я слышал, что Ruby подчиняется этому принципу, а Python - нет. Я не понимаю, почему это так, или если это вообще так.

Эндрю
источник
3
Я не понимаю, почему это не по теме, кто-то может мне это объяснить?
Эндрю
3
Есть пара вопросов; Я исправил это и посылаю это программистам, где подобные обсуждения немного более приветствуются.
Сорвал
1
Ruby не подчиняется этому принципу: Assume exprполучает текущую трассировку стека.
Landei

Ответы:

18

Я никогда раньше не слышал о «Принципе соответствия Теннента» и тем более о его важности для языкового дизайна. Погугление выражений, похоже, ведет к одному блогу Нила Гафтера 2006 года, в котором изложено, что он думает, и как, по его мнению, это должно относиться и к замыканиям. И большинство всех остальных на форумах, кажется, ссылаются на запись Gafter.

Вот, однако, упоминание упомянутого «TCP» Дугласом Крокфордом (имя, которое я знаю и которому доверяю): http://java.sys-con.com/node/793338/ . Частично

Есть некоторые вещи, которые не могут быть заключены таким образом, такие как операторы return и break, которые, как утверждают сторонники принципа соответствия Tennent (или TCP), являются симптомом неприятного запаха. Йоу! Языковой дизайн уже достаточно сложен, не справляясь с обонятельными галлюцинациями. Поэтому, чтобы лучше понять проблему, я купил книгу Теннента 1981 года «Принципы языков программирования».

Оказывается, что принцип соответствия носит описательный , а не предписывающий характер . Он использует его для анализа (ныне забытого) языка программирования Pascal, показывая соответствие между определениями переменных и параметрами процедур. Теннент не считает несоответствие деклараций возврата проблемой .

Поэтому кажется, что название «Принцип соответствия Теннента» используется неправильно, и все, о чем Нил говорит, возможно, следует называть «Воображаемым и, возможно, обобщенным ПТС» Гафтера ... или что-то подобное. В любом случае недостаточно спрятаться за распечатанным занавесом книги

Нас Банов
источник
1
+1 за «Воображаемый и, возможно, обобщенный TCP»
Gafter
9

Я рассматриваю это как часть общего правила, согласно которому хорошо разработанный язык делает то, что программист, естественно, ожидает. Если у меня есть блок кода, который я хочу преобразовать в замыкание, и я обертываю этот блок подходящим синтаксисом, не задумываясь об отдельных строках кода, то я ожидаю, что этот блок будет выполнять то же самое в замыкании, что и он. сделал встроенный. Если некоторые операторы используют ключевое слово «this» (возможно, неявно) и язык заставляет «this», используемый внутри замыкания, ссылаться на анонимный класс, используемый для его представления, а не на класс, который определяет метод, определяющий замыкание, тогда значение эти утверждения изменились, мой блок кода больше не делает то, что я думаю, и мне нужно отследить ошибку и выяснить, как изменить мой код, чтобы он работал в замыкании.

Эту проблему можно также устранить с помощью интегрированной среды разработки с интеллектуальными инструментами рефакторинга, которые могут извлекать замыкания, обнаруживать потенциальные проблемы и даже автоматически корректировать извлеченный код для решения проблем.

JGWeissman
источник
3

Клаус Рейнке: касательно «Языкового дизайна, основанного на семантических принципах»
Теннента Дает интересную интерпретацию принципов:
«Соответствие - это принцип, который позволяет нам сказать, что

let(this=obj, x=5) { .. }  

а также

((function(x) { .. }).call(obj,5))  

должно быть эквивалентным, и что все, что мы можем делать в списках формальных параметров, мы также должны иметь возможность делать в объявлениях и наоборот. "[см. также Reinke, ниже.]

Р.Д. Теннент: Методы проектирования языка, основанные на семантических принципах
"Два метода проектирования языка, основанные на принципах, полученных на основе денотационного подхода к семантике языка программирования, описаны и проиллюстрированы приложением к языку Pascal. Принципами, во-первых, является соответствие между параметрическим и декларативные механизмы, и, во-вторых, принцип абстракции для языков программирования, адаптированных из теории множеств. Несколько полезных расширений и обобщений Паскаля появляются благодаря применению этих принципов, включая решение проблемы параметров массива и средство модульности ».

Клаус Рейнке: «О функциональном программировании, проектировании языков и постоянстве» на Haskell

Kris
источник
Клаус Рейнке: «О функциональном программировании, проектировании языков и постоянстве» на Haskell по адресу community.haskell.org/~claus/publications/fpldp.html
Крис
2

Чтобы ответить на вопрос, почему CP Теннента так важен для языкового дизайна, я хотел бы процитировать Нила Гафтера :

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

Любое нарушение TCP может повредить программисту в будущем, когда он ожидает, что замыкания будут работать как код без замыканий, но обнаружит, что в случае нарушения TCP они этого не делают.

thiton
источник
1

RE Python не следует этому принципу. Как правило, он следует принципу. Основной пример:

>>> x = ['foo']
>>> x
['foo']
>>> x = (lambda: ['foo'])()
>>> x
['foo']

Тем не менее, Python определяет выражения и операторы отдельно. Поскольку ifветви, whileциклы, деструктивное присваивание и другие операторы вообще не могут использоваться в lambdaвыражениях, буква принципа Теннента к ним не относится. Тем не менее, ограничиваясь использованием только выражений Python, все равно получается полная система Тьюринга. Поэтому я не считаю это нарушением принципа; или, скорее, если это нарушает принцип, то никакой язык, который определяет утверждения и выражения отдельно, не может соответствовать этому принципу.

Кроме того, если тело lambdaвыражения захватывает трассировку стека или выполняет другой самоанализ в виртуальной машине, это может вызвать различия. Но, на мой взгляд, это не должно рассматриваться как нарушение. Если exprи (lambda: expr)() обязательно компилировать в один и тот же байт-код, то этот принцип действительно касается компиляторов, а не семантики; но если они могут компилироваться в другой байт-код, мы не должны ожидать, что состояние VM будет одинаковым в каждом случае.

При использовании синтаксиса понимания может возникнуть неожиданность, хотя я считаю, что это также не является нарушением принципа Теннента. Пример:

>>> [x for x in xrange(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [f() for f in [lambda: x for x in xrange(10)]]  # surprise!
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
>>> # application of Tennent principle to first expression
... [(lambda: x)() for x in xrange(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [f() for f in [(lambda x: lambda: x)(x) for x in xrange(10)]]  # force-rebind x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> map(lambda f:f(), map(lambda x: lambda: x, xrange(10)))  # no issue with this form
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Сюрприз - результат того, как определены списочные представления. Вышеупомянутое «неожиданное» понимание эквивалентно следующему коду:

>>> result = []
>>> for x in xrange(10):
...   # the same, mutable, variable x is used each time
...   result.append(lambda: x)
... 
>>> r2 = []
>>> for f in result:
...   r2.append(f())
... 
>>> r2
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]

При таком понимании «неожиданное» понимание выше не так удивительно и не является нарушением принципа Теннента.

wberry
источник