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