Михаил,

А я не понял: почему обсуждаемые конструкции мешают 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, ни в других языках не видел.  (Сам я такое
> свойство вложил в своем полуреализованном языке, но миру от этого мало
> пользы :) )
> >
> > Бойко
>

Ответить