자바스크립트의 함수형 프로그래밍
7920 단어 javascriptprogrammingbeginners
함수로 배열 처리
숫자 배열이 있고 해당 값의 평균과 표준 편차를 계산하려고 한다고 가정합니다. 다음과 같이 기능적이지 않은 스타일로 수행할 수 있습니다.
let data = [1,1,3,5,5]; // This is our array of numbers
// The mean is the sum of the elements divided by the number of elements
let total = 0;
for(let i = 0; i < data.length; i++) total += data[i];
let mean = total/data.length; // mean == 3; The mean of our data is 3
// To compute the standard deviation, we first sum the squares of
// the deviation of each element from the mean.
total = 0;
for(let i = 0; i < data.length; i++) {
let deviation = data[i] - mean;
total += deviation * deviation;
}
let stddev = Math.sqrt(total/(data.length-1)); // stddev == 2
다음과 같이 배열 메서드 map() 및 reduce()를 사용하여 간결한 기능 스타일로 동일한 계산을 수행할 수 있습니다.
// First, define two simple functions
const sum = (x,y) => x+y;
const square = x => x*x;
// Then use those functions with Array methods to compute mean and stddev
let data = [1,1,3,5,5];
let mean = data.reduce(sum)/data.length; // mean == 3
let deviations = data.map(x => x-mean);
let stddev = Math.sqrt(deviations.map(square).reduce(sum)/(data.length-1));
stddev // => 2
이 새 버전의 코드는 첫 번째 코드와 상당히 다르게 보이지만 여전히 개체에 대한 메서드를 호출하므로 일부 개체 지향 규칙이 남아 있습니다. map() 및 reduce() 메서드의 기능적 버전을 작성해 보겠습니다.
const map = function(a, ...args) { return a.map(...args); };
const reduce = function(a, ...args) { return a.reduce(...args); };
이러한 map() 및 reduce() 함수를 정의하면 평균 및 표준 편차를 계산하는 코드는 이제 다음과 같습니다.
const sum = (x,y) => x+y;
const square = x => x*x;
let data = [1,1,3,5,5];
let mean = reduce(data, sum)/data.length;
let deviations = map(data, x => x-mean);
let stddev = Math.sqrt(reduce(map(deviations, square), sum)/(data.length-1));
stddev // => 2
고차 함수
고차 함수는 하나 이상의 함수를 인수로 사용하고 새 함수를 반환하는 함수에 대해 작동하는 함수입니다.
// This higher-order function returns a new function that passes its
// arguments to f and returns the logical negation of f's return value;
function not(f) {
return function(...args) { // Return a new function
let result = f.apply(this, args); // that calls f
return !result; // and negates its result.
};
}
const even = x => x % 2 === 0; // A function to determine if a number is even
const odd = not(even); // A new function that does the opposite
[1,1,3,5,5].every(odd) // => true: every element of the array is odd
이 not() 함수는 함수 인수를 취하고 새 함수를 반환하기 때문에 고차 함수입니다. 또 다른 예로, 다음에 나오는 mapper() 함수를 고려하십시오. 함수 인수를 사용하여 해당 함수를 사용하여 하나의 배열을 다른 배열에 매핑하는 새 함수를 반환합니다. 이 함수는 앞에서 정의한 map() 함수를 사용하며 두 함수가 어떻게 다른지 이해하는 것이 중요합니다.
// Return a function that expects an array argument and applies f to
// each element, returning the array of return values.
// Contrast this with the map() function from earlier.
function mapper(f) {
return a => map(a, f);
}
const increment = x => x+1;
const incrementAll = mapper(increment);
incrementAll([1,2,3]) // => [2,3,4]
다음은 f와 g의 두 함수를 사용하고 f(g())를 계산하는 새 함수를 반환하는 또 다른 보다 일반적인 예입니다.
// Return a new function that computes f(g(...)).
// The returned function h passes all of its arguments to g, then passes
// the return value of g to f, then returns the return value of f.
// Both f and g are invoked with the same this value as h was invoked with.
function compose(f, g) {
return function(...args) {
// We use call for f because we're passing a single value and
// apply for g because we're passing an array of values.
return f.call(this, g.apply(this, args));
};
}
const sum = (x,y) => x+y;
const square = x => x*x;
compose(square, sum)(2,3) // => 25; the square of the sum
기능의 부분적 적용
함수 f의 bind() 메서드는 지정된 컨텍스트에서 지정된 인수 집합을 사용하여 f를 호출하는 새 함수를 반환합니다. 함수를 객체에 바인딩하고 인수를 부분적으로 적용한다고 말합니다. bind() 메서드는 부분적으로 왼쪽에 인수를 적용합니다. 즉, bind()에 전달한 인수는 원래 함수에 전달된 인수 목록의 시작 부분에 배치됩니다.
// The arguments to this function are passed on the left
function partialLeft(f, ...outerArgs) {
return function(...innerArgs) { // Return this function
let args = [...outerArgs, ...innerArgs]; // Build the argument list
return f.apply(this, args); // Then invoke f with it
};
}
// The arguments to this function are passed on the right
function partialRight(f, ...outerArgs) {
return function(...innerArgs) { // Return this function
let args = [...innerArgs, ...outerArgs]; // Build the argument list
return f.apply(this, args); // Then invoke f with it
};
}
// The arguments to this function serve as a template. Undefined values
// in the argument list are filled in with values from the inner set.
function partial(f, ...outerArgs) {
return function(...innerArgs) {
let args = [...outerArgs]; // local copy of outer args template
let innerIndex=0; // which inner arg is next
// Loop through the args, filling in undefined values from inner args
for(let i = 0; i < args.length; i++) {
if (args[i] === undefined) args[i] = innerArgs[innerIndex++];
}
// Now append any remaining inner arguments
args.push(...innerArgs.slice(innerIndex));
return f.apply(this, args);
};
}
// Here is a function with three arguments
const f = function(x,y,z) { return x * (y - z); };
// Notice how these three partial applications differ
partialLeft(f, 2)(3,4) // => -2: Bind first argument: 2 * (3 - 4)
partialRight(f, 2)(3,4) // => 6: Bind last argument: 3 * (4 - 2)
partial(f, undefined, 2)(3,4) // => -6: Bind middle argument: 3 * (2 - 4)
이러한 부분적 적용 기능을 통해 이미 정의한 기능 중에서 흥미로운 기능을 쉽게 정의할 수 있습니다.
const increment = partialLeft(sum, 1);
const cuberoot = partialRight(Math.pow, 1/3);
cuberoot(increment(26)) // => 3
부분 적용은 다른 고차 함수와 결합할 때 훨씬 더 흥미로워집니다. 예를 들어 다음은 구성 및 부분 적용을 사용하여 방금 표시된 이전 not() 함수를 정의하는 방법입니다.
const not = partialLeft(compose, x => !x);
const even = x => x % 2 === 0;
const odd = not(even);
const isNumber = not(isNaN);
odd(3) && isNumber(2) // => true
구성 및 부분 적용을 사용하여 극단적인 기능 스타일로 평균 및 표준 편차 계산을 다시 실행할 수도 있습니다.
// sum() and square() functions are defined above. Here are some more:
const product = (x,y) => x*y;
const neg = partial(product, -1);
const sqrt = partial(Math.pow, undefined, .5);
const reciprocal = partial(Math.pow, undefined, neg(1));
// Now compute the mean and standard deviation.
let data = [1,1,3,5,5]; // Our data
let mean = product(reduce(data, sum), reciprocal(data.length));
let stddev = sqrt(product(reduce(map(data,
compose(square,
partial(sum, neg(mean)))),
sum),
reciprocal(sum(data.length,neg(1)))));
[mean, stddev] // => [3, 2]
평균과 표준 편차를 계산하는 이 코드는 전적으로 함수 호출입니다. 관련된 연산자가 없으며 괄호의 수가 너무 많아 이 JavaScript가 Lisp 코드처럼 보이기 시작했습니다.
다시 말하지만 이것은 내가 JavaScript 프로그래밍을 옹호하는 스타일은 아니지만 JavaScript 코드가 얼마나 깊이 기능할 수 있는지 알아보는 흥미로운 연습입니다.
Reference
이 문제에 관하여(자바스크립트의 함수형 프로그래밍), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/digomic/functional-programming-in-javascript-m11텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)