Примитивный тип как функция
Feb. 11th, 2015 09:41 pm![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Мне сегодня на Stackoverflow попался изумительной красоты вопрос про javascript. Я, как обычно, невнимательно его прочитал и ответил немного не в кассу, ну, меня быстро поправили.
Вопрос чисто собеседовательный, хотя я такую задачку по неопытности как-то раз решал в жизни – и крепко в своё время затрахалася.
Задача: нужно сконструировать такую функцию add, которая делает вот так
add(1) >> 1
add(1)(2) >> 3
add(2)(3)(4) >> 9
Цепочка вызовов может быть любой длины, в скобках только числа.
Сначала может показаться, что задачка нерешаема. Потом – что нам нужно локально расширить объект Number какой-то конструкцией, которая позволит вызывать Number как функцию. Это можно сделать – но получается очень громоздко. В самом деле надо идти с другой стороны – делать такую функцию, которая при попытке её с чем нибудь сложить кастится в число.
Любопытно, что если переделывать Number получается практически то-же самое, просто значительно длиннее и от самого намбера там ничего не остаётся.
Сделать функцию, которая при попытке её с чем-нибудь сложить “прикидывается” числом совсем просто.
Дело в том, что любая функция в js – объект. У неё есть метод toString, который и управляет кастингом. Собственно, он и вызывается неявно, когда вычисляемое выражение требует привдения к примитивному типу. Если toString наследуется от прототипа – он вернёт исходный текст функции. Но мы можем его подменить – и он станет возвращать число.
Хак целиком выглядит вот так:
var add = (function() { var factory = function(value) { var fn = function(num) { return factory(value + num) }; fn.toString = function() {return value}; return fn; }; return factory(0); })();
Офигенно, по-моему, с эстетической точки зрения. На каждом вызове функции возвращается новая функция, которая скрыто каррирована значением предыдущего шага и которая прикидывается числом, если её закастить в примитивный тип.
Такой очень хитрый итератор.
Использовать в жизни я бы такое, правда, не посоветовал – оно mind-blowing, медленное и хрупкое. Как и всё, что красивое и бесполезное )
no subject
Date: 2015-02-12 12:05 pm (UTC)А если вам потом понадобится partial application функции subtract?
no subject
Date: 2015-02-12 08:31 pm (UTC)no subject
Date: 2015-02-13 02:51 am (UTC)в) Тред на хабре http://habrahabr.ru/post/226325/ (если не видели), но вопрос про add я встречал намного раньше, странно что на SO он появился только сейчас.
no subject
Date: 2015-02-13 04:07 am (UTC)Это примерно как если бы вы смотрели на на f=x^2 и говорили «О, это же интеграл» только из тех соображений, что существует f=x, чья первообразная x^2/2.
-------
На SO уже нашли клон вопроса этого от 2011. На Хабре – наверное, видел, я его часто читаю – но в памяти не отложилось. Там кста не совсем то-же самое – накрытие valueOf не оптимальный выбор, лучше toString подменять.