Comments 47
Ну что, прикольно. Можно людям предлагать как альтернативу arguments.callee.
Но, с другой стороны, слишком много магии. Проще дать имя функции и вызывать родителя по имени, как в вашем первом примере.
Но, с другой стороны, слишком много магии. Проще дать имя функции и вызывать родителя по имени, как в вашем первом примере.
Думаю это чисто учебный пример — применение одного из шаблонов проектирования функционального программирования (Y-комбинатор) в javaScript.
Очень полезная статья как для изучения функционального программирования так и javaScript. Побольше бы таких.
Очень полезная статья как для изучения функционального программирования так и javaScript. Побольше бы таких.
Полностью согласен, что статья хороша как учебная. Нужно осваивать новые техники и подходы, особенно принципиально отличающиеся от тех, что мы повсеместно используем, пусть даже на таких, казалось бы, простых примерах. И язык выбран подходящим образом: поддерживает анонимные функции, но в месте с тем не мыслится нами, как правило, как функциональный, будучи таковым.
Тем не менее, чем огранничиться парадоксальным комбинатором Карри Y, можно было б упомянуть о комбинаторе Θ, предложенным Тьюрингом (1937). Он с точки зрания лямбда-исчисления лучше в том смысле, что Θ(F) редуцируется до F(Θ(F)), в то время как Y таковым свойством не обладает, ограничивая себя лишь равенством Y(F)=F(Y(F)).
Тем не менее, чем огранничиться парадоксальным комбинатором Карри Y, можно было б упомянуть о комбинаторе Θ, предложенным Тьюрингом (1937). Он с точки зрания лямбда-исчисления лучше в том смысле, что Θ(F) редуцируется до F(Θ(F)), в то время как Y таковым свойством не обладает, ограничивая себя лишь равенством Y(F)=F(Y(F)).
По мотивам этой статьи, творчески переработав, записал скринкаст о реализации Y-комбинатора на JavaScript: youtu.be/clYMNxScsFQ
Сначала подумал, что речь о бизнес-инкубаторе y-combinator и как туда попасть ))
Вот уж эти стартапы, скоро снится начнут.
Вот уж эти стартапы, скоро снится начнут.
Двусмысленный заголовок =)
Господи, а зачем тут JS? Типа, чтобы даже последние дебилы веб-обезьяны типичный посетитель Хабра понял? На традиционной схеме это на порядок понятнее и красивее.
Лямбда-счисление:
Схема:
Лямбда-счисление:
Y = λf.(λx.f (x x)) (λx.f (x x))
Схема:
(define Y (λ (f) ((λ (rec) (f (λ arg (apply (rec rec) arg)))) (λ (rec) (f (λ arg (apply (rec rec) arg)))))))
UFO just landed and posted this here
Об этом вы лучше автора оригинала спросите.
на порядок понятнее и красивееЯ с лиспом не знаком, и пока искал пару 3-й скобке в вашем втором выражении окончательно запутался. В статье же все предельно доступно, на простом и понятном многим языке.
Что за дурацкая привычка псевдолисперов выкладывать чанки кода в одну строку? Лисп — ни разу не язык однострочников, это самый вертикальный язык из всех мне известных, и в этом его большое преимущество.
(defn Y [r]
(letfn [(rec[f] (f f))]
(rec (fn[g]
(r (fn[x] ((rec g) x)))))))
Вышло все равно не мгновенно очевидно, но это изза сложности понимая самого комбинатора.
Не создавайте, пожалуйста, языку дурную славу, ее у него и так достаточно.
(defn Y [r]
(letfn [(rec[f] (f f))]
(rec (fn[g]
(r (fn[x] ((rec g) x)))))))
Вышло все равно не мгновенно очевидно, но это изза сложности понимая самого комбинатора.
Не создавайте, пожалуйста, языку дурную славу, ее у него и так достаточно.
Форматирование поехало. Вот нормальная версия: pastebin.com/gWWAgtGc
Интересный у вас fact(-2) получается.
Вместо того, чтобы «маскировать уродство» не лучше ли было взять подходящий инструмент? Хаскель для того и придумали.
Вместо того, чтобы «маскировать уродство» не лучше ли было взять подходящий инструмент? Хаскель для того и придумали.
Нет, давайте уже поговорим о динамической и статической типизации и пригодности языков подмножества ECMA для функционального программирования.
Давайте поговорим. Что Вас беспокоит?
Сегодня меня беспокоят цены на редкоземельные металлы. А обсудить мы можем то, о чем я писал в первом комментарии в ветке.
Неплохо было бы привести аргументы, чтобы было что обсуждать.
Так и приводите. Мои — у вас перед глазами.
Если желаете — могу дать их подробнее.
1. В языках с динамической типизацией требуется внимательно следить за аргументами. Это не только идеологически неправильно, но и не удобно.
2. Также скриптовые языки, мягко говоря, не выразительны, когда дело доходит до функционального программирования.
Теперь я написал это три раза. Ваши аргументы?
Если желаете — могу дать их подробнее.
1. В языках с динамической типизацией требуется внимательно следить за аргументами. Это не только идеологически неправильно, но и не удобно.
2. Также скриптовые языки, мягко говоря, не выразительны, когда дело доходит до функционального программирования.
Теперь я написал это три раза. Ваши аргументы?
Ааа. Так это вы называете аргументами.
Ну холивар динамическая vs статическая типизация вообще к теме не имеет ни малейшего отношения
А второе — это спорный вопрос. На новой версии языка, которой можно будет пользоваться на сервере уже где-то через полгода-год получается вполне изящно:
Ну холивар динамическая vs статическая типизация вообще к теме не имеет ни малейшего отношения
А второе — это спорный вопрос. На новой версии языка, которой можно будет пользоваться на сервере уже где-то через полгода-год получается вполне изящно:
var fact = Y(#(callee) {
#(num) { num > 1 ? num * callee(num - 1) : 1 }
});
Новая версия, которая будет когда-то — это очень хорошо. Пока можно было взять старую версию лиспа хаскеля или *мл и сделать красиво.
Это не спорный вопрос и не холивар. Я просто хотел отметить, что не следует забивать гвозди селедкой.
Это не спорный вопрос и не холивар. Я просто хотел отметить, что не следует забивать гвозди селедкой.
Пока кроме старой версии Javascript нельзя взять ни новую версию ни Лисп или Хаскель.
А на сервере можно взять и Лисп с Хаскелем и новую версию JavaScript.
Хотя вру. На новой версии уже можно писать даже для клиента.
Еще аргументы есть?
А на сервере можно взять и Лисп с Хаскелем и новую версию JavaScript.
Хотя вру. На новой версии уже можно писать даже для клиента.
Еще аргументы есть?
Полно!
Блог называется «программирование», а не яваскрипт, а это значит, что выбор языка для иллюстрации У комбинатора был осознанным и ошибочным.
Все ваши размышления о сервере и клиенте тут совершенно не при чём, потому что язык был взят для иллюстрации, а не для решения конкретной задачи на клиенте.
Если бы вы взяли новую редакцию яваскрипта и, используя её написали статью о У комбинаторе — я бы снял шляпу и поставил большой плюс, а пока — все ещё селёдка.
Блог называется «программирование», а не яваскрипт, а это значит, что выбор языка для иллюстрации У комбинатора был осознанным и ошибочным.
Все ваши размышления о сервере и клиенте тут совершенно не при чём, потому что язык был взят для иллюстрации, а не для решения конкретной задачи на клиенте.
Если бы вы взяли новую редакцию яваскрипта и, используя её написали статью о У комбинаторе — я бы снял шляпу и поставил большой плюс, а пока — все ещё селёдка.
А какая разница, какой язык? Javascript знает очень много людей, синтаксис у него очень простой и понятный. Если вам интересно, вот код на последней версии языка:
var Y = # (h) {
# (# (f) {
f(f)
})(# (f) {
h(# (n) { # f(f)(n) })
})
};
var fact = Y(# (callee) {
#(num) { num > 1 ? num * callee(num - 1) : 1 }
});
Разница очевидна, если сравнить код приведенный вами, код приведенный в седьмом шаге и код из коммента, который кстати тоже заминустовали: habrahabr.ru/blogs/programming/118927/#comment_3880779
В функциональном программировании самое главное понять принцип. Второе главное — реализовать с помощью _удобного_ инструмента.
И ещё одно. Человек, который может в этот код — может в ФП -)
В функциональном программировании самое главное понять принцип. Второе главное — реализовать с помощью _удобного_ инструмента.
И ещё одно. Человек, который может в этот код — может в ФП -)
Наверно вы в танке и не заметили что статья о Y-комбинаторе а не о JavaScript. А динамическая типизация это не то что +'123' + 1 = 124 это то что функции можно делать полиморфными
Вы наверное не очень в программирование.
«123» + 1 = 124 это dynamic cast
Полиморфизм отлично работает и со статической типизацией.
То что я имел в виду пишется так: «Dynamic typing may result in runtime type errors—that is, at runtime, a value may have an unexpected type, and an operation nonsensical for that type is applied.»
Матчасть, матчасть и еще раз матчасть.
«123» + 1 = 124 это dynamic cast
Полиморфизм отлично работает и со статической типизацией.
То что я имел в виду пишется так: «Dynamic typing may result in runtime type errors—that is, at runtime, a value may have an unexpected type, and an operation nonsensical for that type is applied.»
Матчасть, матчасть и еще раз матчасть.
> язык не поддерживает механизм рекурсии, но поддерживает анонимные функции
а можно пример?
а можно пример?
Вообще подобная статья была в блоге питона, я тогда чуть моск не сломал, но мне понравилось :) Но как там же и пояснили практического смысла в этом нет (выходит затратнее), но мозги развивает.
Не думал, что на JS для этого нужно столько кода…
На VB.Net и C# намного компактнее:
C#
VB.Net
Delegate Function SelfApplicable(Of TReturn)(ByVal self As SelfApplicable(Of TReturn)) As TReturn
Dim YC As SelfApplicable(Of Func(Of Func(Of Func(Of Integer, Integer), Func(Of Integer, Integer)), Func(Of Integer, Integer))) = _
Function(y) Function(f) Function(x) f(y(y)(f))(x)
Dim factorial = YC(YC)(Function(fac) Function(x) If(x = 0, 1, x * fac(x — 1)))
P.S. <code> не пашет =(
На VB.Net и C# намного компактнее:
C#
VB.Net
Delegate Function SelfApplicable(Of TReturn)(ByVal self As SelfApplicable(Of TReturn)) As TReturn
Dim YC As SelfApplicable(Of Func(Of Func(Of Func(Of Integer, Integer), Func(Of Integer, Integer)), Func(Of Integer, Integer))) = _
Function(y) Function(f) Function(x) f(y(y)(f))(x)
Dim factorial = YC(YC)(Function(fac) Function(x) If(x = 0, 1, x * fac(x — 1)))
P.S. <code> не пашет =(
Самоотправилось…
C#
delegate TReturn SelfApplicable<TReturn>(SelfApplicable<TReturn> self);
SelfApplicable<Func<Func<Func<int, int>, Func<int, int>>, Func<int, int>>>
YC = y => f => x => f(y(y)(f))(x);
var factorial = YC(YC)(fac => x => x = 0? 1: x * fac(x — 1));
C#
delegate TReturn SelfApplicable<TReturn>(SelfApplicable<TReturn> self);
SelfApplicable<Func<Func<Func<int, int>, Func<int, int>>, Func<int, int>>>
YC = y => f => x => f(y(y)(f))(x);
var factorial = YC(YC)(fac => x => x = 0? 1: x * fac(x — 1));
Может я олдфаг, но зачем для обычной рекурсии такие непонятные коды городить?
Sign up to leave a comment.
Получение Y-комбинатора в 7 простых шагов