Потому что от того, была выполнена эта оптимизация или нет, зависит
семантика неконстантных методов объекта-функции. В исходном
джаваскрипте TCO не было. Сейчас она допускается и для этого, как
минимум, метод arguments у объектов-функций объявлен deprecated.

2017-08-07 13:04 GMT+03:00 Andrei Klimov <andrei.kli...@gmail.com>:
> Михаил,
>
> А я не понял: почему обсуждаемые конструкции мешают Tail Call Optimization?
> По идее, если вызов действительно хвостовой (поверх него ничего нет), то что
> мешает это заметить и преобразовать в цикл?
>
> Андрей
>
> 7 авг. 2017 г. 11:20 пользователь "Mike Potanin" <mpota...@gmail.com>
> написал:
>
>> На мой взглад доступ с фреймам вызова функции через специальный объект
>> в джаваскрипте - решение неудачное, так как оно не позволяет
>> производить TCO. В функциональном языке какие-то варианты TCO очень
>> важны, так как руками рекурсию в цикл превратить не получится.
>>
>> 2017-08-04 23:56 GMT+03:00 Александр Коновалов <a.v.konovalo...@mail.ru>:
>> > Добрый вечер, Бойко!
>> >
>> > Понял вашу мысль. Вы фактически предлагаете аналог указателя «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:boyk...@gmail.com]
>> > Sent: Friday, August 4, 2017 10:28 AM
>> > To: refal@botik.ru
>> > 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, ни в других языках не видел.  (Сам я такое свойство вложил
>> > в своем полуреализованном языке, но миру от этого мало пользы :) )
>> >
>> > Бойко

Ответить