JavaScript. Подробное руководство, 6-е издание, стр. 105

<b>// Ниже приводится функция, принимающая три аргумента </b>

<b>var f = function(x,y,z) { return x * (у - z); };</b>

<b>// Обратите внимание на отличия между следующими тремя частичными применениями </b>

<b>partialLeft(f, 2)(3,4) // =&gt; -2: Свяжет первый аргумент: 2 * (3 - 4)</b>

<b>partialRight(f, 2)(3,4) // =&gt; 6: Свяжет последний аргумент: 3 * (4 - 2)</b>

<b>partial(f, undefined, 2)(3,4) // =&gt; -6: Свяжет средний аргумент: 3 * (2 - 4)</b>

Эти функции частичного применения позволяют легко объявлять новые функции на основе уже имеющихся функций. Например:

<b>var increment = partialLeft(sum, 1); </b>

<b>var cuberoot = partialRight(Math.pow, 1/3);</b>

<b>String.prototype.first = partial(String.prototype.charAt, 0);</b>

<b>String.prototype.last = partial(String.prototype.substr, -1, 1);</b>

Прием частичного применения становится еще более интересным, когда он используется в комбинации с функциями высшего порядка. Например, ниже демонстрируется еще один способ определения функции

<b>not()</b>
, представленной выше, за счет совместного использования приемов композиции и частичного применения:

<b>var not = partialLeft(compose, function(x) { return !x; });</b>

<b>var even = function(x) { return x % 2 === 0; };</b>

<b>var odd = not(even);</b>

<b>var isNumber = not(isNaN)</b>

Прием композиции и частичного применения можно также использовать для вычисления среднего значения и стандартного отклонения в крайне функциональном стиле:

<b>var data = [1,1.З,5,5]; // Исходные данные</b>

<b>var sum = function(x.y) { return x+y; }; // Две элементарные функции</b>

<b>var product = function(x,у) { return x*y; };</b>

<b>var neg = partial(product, -1); // Определения других функций</b>

<b>var square = partial(Math.pow, undefined, 2);</b>

<b>var sqrt = partial(Math.pow, undefined, .5);</b>

<b>var reciprocal = partial(Math.pow, undefined, -1);</b>

<b>// Вычислить среднее и стандартное отклонение. Далее используются только функции</b>

<b>// без каких либо операторов, отчего программный код начинает напоминать</b>

<b>// программный код на языке Lisp!</b>

<b>var mean = product(reduce(data, sum), reciprocal(data.length)); </b>

<b>var stddev = sqrt(product(reduce(map(data, compose(square,</b>

<b>  partial(sum, neg(mean)))), sum),</b>

<b>  reciprocal(sum(data.length,-1))));</b>

8.8.4. Мемоизация

В разделе 8.4.1 была определена функция нахождения факториала, которая сохраняет ранее вычисленные результаты. В функциональном программировании такого рода кэширование называется мемоизацией (memorization). В следующем примере демонстрируется функция

<b>memoize()</b>
высшего порядка, которая принимает функцию в виде аргумента и возвращает ее мемоизованную версию:

<b>// Возвращает мемоизованную версию функции f. Работает, только если все возможные </b>

<b>// аргументы f имеют отличающиеся строковые представления, </b>

<b>function memoize(f) {</b>

<b>  var cache = {}; // Кэш значений сохраняется в замыкании, </b>

<b>  return function() {</b>

<b>    // Создать строковую версию массива arguments для использования </b>

<b>    // в качестве ключа кэша.</b>

<b>    var key = arguments.length + Array.prototype.join.call(arguments,&quot;,&quot;)</b>

<b>    if (key in cache) return cache[key];</b>

<b>    else return cache[key] = f.apply(this, arguments);</b>

<b>  };</b>

<b>}</b>

Функция

<b>memoize()</b>
создает новый объект для использования в качестве кэша и присваивает его локальной переменной, благодаря чему он остается доступным (через замыкание) только для возвращаемой функции. Возвращаемая функция преобразует свой массив
<b>arguments</b>
в строку и использует ее как имя свойства объекта-кэша. Если значение присутствует в кэше, оно просто возвращается в качестве результата. В противном случае вызывается оригинальная функция, вычисляющая значение для заданной комбинации значений аргументов; полученное значение помещается в кэш и возвращается. Следующий фрагмент демонстрирует, как можно использовать функцию
<b>memoize():</b>

<b>// Возвращает наибольший общий делитель двух целых чисел, используя </b>

<b>// алгоритм Эвклида: </b><a href="http://en.wikipedia.org/wiki/Euclidean_algorithm"><b>http://en.wikipedia.org/wiki/Euclidean_algorithm</b></a>

<b>function gcd(a.b) { // Проверка типов а и b опущена</b>

<b>  var t; // Временная переменная для обмена</b>

<b>  if (а &lt; b) t=b, b=a, a=t; // Убедиться, что а &gt;= b</b>

<b>  while(b ! = 0) t=b, b = a%b, a=t; // Это алгоритм Эвклида поиска НОД </b>

<b>  return а;</b>