Михаил, спасибо! Теперь понял, что речь идет о тонкостях JS. А я думал, что речь о функциональном языке, а пример на JS лишь иллюстрировал идею и обсуждалось предложение включить в язык обозначение для вызова ближайшего объемлющего ламбда-выражения по аналогии с this как ссылкой на ближайший объемлющий объект.
Я не проблем вижу проблем с ТСО для такого расширенного лямбда-выражения, потому и удивился. Это было мое недопонимание. Спасибо, вопрос закрыт. Всего наилучшего, Андрей 2017-08-07 14:11 GMT+03:00 Mike Potanin <[email protected]>: > Потому что от того, была выполнена эта оптимизация или нет, зависит > семантика неконстантных методов объекта-функции. В исходном > джаваскрипте TCO не было. Сейчас она допускается и для этого, как > минимум, метод arguments у объектов-функций объявлен deprecated. > > 2017-08-07 13:04 GMT+03:00 Andrei Klimov <[email protected]>: > > Михаил, > > > > А я не понял: почему обсуждаемые конструкции мешают Tail Call > Optimization? > > По идее, если вызов действительно хвостовой (поверх него ничего нет), то > что > > мешает это заметить и преобразовать в цикл? > > > > Андрей > > > > 7 авг. 2017 г. 11:20 пользователь "Mike Potanin" <[email protected]> > > написал: > > > >> На мой взглад доступ с фреймам вызова функции через специальный объект > >> в джаваскрипте - решение неудачное, так как оно не позволяет > >> производить TCO. В функциональном языке какие-то варианты TCO очень > >> важны, так как руками рекурсию в цикл превратить не получится. > >> > >> 2017-08-04 23:56 GMT+03:00 Александр Коновалов <[email protected] > >: > >> > Добрый вечер, Бойко! > >> > > >> > Понял вашу мысль. Вы фактически предлагаете аналог указателя «this» > (или > >> > «self») применительно к безымянным функциям. Идея интересная, но у > меня > >> > затык не с синтаксической конструкцией, а с представлением во время > >> > выполнения. Хоть с именами, хоть с this’ом взаимная рекурсия с > возвратом > >> > указателя неизбежно конфликтует (а) с требованиями к равенству двух > >> > указателей на функцию, (б) с использованием простого счётчика ссылок > для > >> > управления памятью. > >> > > >> > Почему нет такой конструкции в большинстве языков программирования? > >> > Во-первых, инертность мышления (а что, и так тоже можно?), во-вторых, > нужна > >> > редко. Обычно ко вложенной безымянной функции относятся не как к > функции, а > >> > как к блоку кода, который воспринимается как некий фрагмент устойчивой > >> > конструкции, функции map, играющей роль цикла. Вложенные безымянные > функции > >> > обычно небольшие и играют роль части выражения. Если нужно выразить > более > >> > сложную логику, то её оформляют как отдельную функцию, которой уже > логично > >> > дать соответствующее имя (независимо от наличия рекурсии внутри). > Вообще, > >> > лучший способ прокомментировать блок кода — не писать комментарий > перед ним, > >> > а вынести его в отдельную функцию и дать ей ясное понятное название. > >> > > >> > > >> > Не могу не поделиться одной историей. В этом году я разрешил студентам > >> > сдавать лабораторные на необычных языка программирования, при этом > одна > >> > лабораторная засчитывалась за три. Среди таких языков был Smalltalk. > Порог > >> > вхождения у него низкий: посмотрев на примеры кода и найдя > документацию по > >> > стандартной библиотеке, уже можно писать немаленькие (сотни строк > кода) > >> > работающие программы. При этом вникать в устройство языка не > обязательно. > >> > > >> > Так вот. «Условный оператор» в Smalltalk выглядит так: (x < y) ifTrue: > >> > […] ifFalse: […]., «цикл» — [x < y] whileTrue: […].. Так вот. Это не > >> > условный оператор и не цикл. Текст в квадратных скобках — это не блок > кода > >> > (как {…} в C++), а лямбда. Безымянная функция (вернее, безымянный > класс с > >> > методом call, если я ничего не путаю). Булевский класс имеет двух > потомков, > >> > соответственно, True и False. У первого метод ifTrue: f1 ifFalse f2. > >> > выполняет замыкание f1, у второго — f2. У самого класса замыкания, > помимо > >> > метода call, есть метод whileTrue: func., который вычисляет себя и > свой > >> > аргумент в цикле, пока сам себе возвращает значение True. > >> > > >> > А значит, вместо (x < y) ifTrue: […] ifFalse: [……]. можно написать: f1 > >> > := […]. f2 := [……]. (x < y) ifTrue: f1 ifFalse f2. Аналогично с > «циклом» > >> > whileTrue: f3 := [x < y]. f4 := […]. f3 whileTrue: f4.. > >> > > >> > Когда я это объяснял студентам (и делал замены из предыдущего абзаца), > >> > только что написавшим (и правильно написавшим) лабораторную, они > удивлялись. > >> > Оказывалось, что в языке нет управляющих конструкций кроме создания > блока, > >> > вызова метода и ^ (так обозначается возврат из метода). Ветвление и > цикл — > >> > методы библиотечных классов. > >> > > >> > Это я рассказал к тому, что безымянные функции вкупе с функциями > >> > стандартной библиотеки (map, fold, filter и другие) воспринимаются как > >> > цельные синтаксические конструкции, фактически, как встроенные > операторы > >> > языка. Помимо Smalltalk’а (а он позиционируется как > >> > объектно-ориентированный, а не функциональный), могучая синтаксическая > >> > поддержка таких конструкций есть в Ruby и Kotlin’е (не > программировал, могу > >> > что-то путать ошибаться). В последнем, например, если функция/метод > >> > принимает последним аргументом функцию, то её можно записывать как > просто > >> > блок в фигурных скобках _вне_ круглых скобок: вместо foo(x, y, {…}) > можно > >> > писать foo(x, y) {…}. Если аргумент единственный — скобки не нужны: > foo({…}) > >> > эквивалентно foo {…}. Что и позволяет писать конструкции, выглядящие > почти > >> > как нативные синтаксические конструкции (типа if(…) {…}). > >> > > >> > -----Original Message----- > >> > From: Boyko Bantchev [mailto:[email protected]] > >> > Sent: Friday, August 4, 2017 10:28 AM > >> > To: [email protected] > >> > Subject: Re: FW: Рефал умер? > >> > > >> > Здравствуйте, Александр! > >> > > >> >> Вы не могли бы пояснить, что вы имеете ввиду под «цитированием себя и > >> >> охватывающей функции при помощи … стандартной пары знаков или имён»? > >> > > >> > Имею ввиду возможность, заложенную в языке, любой функции вызывать > себя > >> > через какое-то фиксированное, универсальное для этой роли имя. > >> > Ну, или передавать свой адрес кому-то еще. Подобно местоимениям «я» > или > >> > «себя»/«себе» в человеческой речи — человек говорит о себе, не > нуждаясь в > >> > имени. Местоимение одно и то же, но относится к разным людям в > зависимости > >> > от того, кто говорит. Конкретный синтаксис неважен. > >> > > >> > Один из совсем немногих языков, где это имеется — это JavaScript. > >> > Дам пример на нем. > >> > > >> > В этом языке у каждой функций имеется (составная) переменная > arguments, > >> > а у arguments имеется часть callee. Так вот, arguments.callee — это > то, о > >> > чем я говорю. В результате можно написать, скажем, анонимный > рекурсивный > >> > факториал: > >> > > >> > function(n) {return n<2 ? 1 : n*arguments.callee(n-1)} > >> > > >> > и вызвать его можно так: > >> > > >> > (function(n) {return n<2 ? 1 : n*arguments.callee(n-1)})(5) > >> > > >> > (или передать кому-нибудь как значение, а вызывать будет уже он сам). > >> > > >> > Еще пример: обращение связанного списка функцией reverse. > >> > reverse создает вложенную функцию с двумя аргументами (из первого она > >> > накапливает результат во второй) и тут же ее вызывает. Вложенная > функция > >> > рекурсивна и анонимна. > >> > > >> > function reverse(x) { > >> > return (function(x,y) { > >> > if (x) { > >> > var r = x > >> > x = x.next > >> > r.next = y > >> > return arguments.callee(x,r) > >> > } > >> > return y > >> > })(x,null) > >> > } > >> > > >> > (А список может быть, скажем, такой: > >> > > >> > list = {data:1} > >> > list = {data:2, next:list} > >> > list = {data:3, next:list} > >> > ) > >> > > >> > Иногда полезно подобным стандартным анонимным образом вызывать и > >> > охватывающую функцию, возможно даже и ту, которая, в свою очередь, ее > >> > охватывает — это позволяет уже взаимную анонимную рекурсию, но таких > средств > >> > ни в JavaScript, ни в других языках не видел. (Сам я такое свойство > вложил > >> > в своем полуреализованном языке, но миру от этого мало пользы :) ) > >> > > >> > Бойко >
