JS의 파이핑 또는 Elm이 부분적 적용에 대해 가르쳐준 것

파이프 운영자가 JS에 오는 것에 대해 몇 가지recent talk가 있었습니다. 나는 이 제안에 대해 흥분하지만 Elm에서 기능적 패턴을 배우는 데 약간의 어려움을 겪었기 때문에 지금입니다.

파이프 오퍼레이터란?



파이프 연산자는 한 함수의 출력을 다른 함수로 "파이프"합니다.

그래서 글을 쓰는 것보다

const result = c(b(a(x)));


또는 내가 선호하는 대로 다음과 같이 작성합니다.

const one = a(x);
const two = b(one);
const result = c(two);


다음과 같이 작성할 수 있습니다.

const result = a(x) |> b |> c;


JavaScript에는 .map() , .filter().reduce() 와 같은 연결 방법과 유사한 것이 있습니다.

그런 이유로 JS에서 파이핑을 탐색하고 Elm에서 배운 내용을 탐색하기 위한 스탠드로 .map()를 사용할 것입니다.

JS 및 Elm의 매핑



기본.map() 예부터 시작하겠습니다.

const square = (n) => n ** 2;
console.log([1, 2, 3].map(square));
// [1, 4, 9]


이것이 하는 일은 배열의 모든 항목에 square(n) 함수를 적용하고 해당 제곱 값이 포함된 새 배열을 반환하는 것입니다.

이는 Elm에서 수행되는 방식과 유사합니다.

List.map square [1, 2, 3]


익명 화살표 기능을 사용하여 JS에서 위의 코드를 작성하는 또 다른 방법이 있습니다.

console.log([1, 2, 3].map(n => square(n)));


얼핏 보면 이 두 가지는 비슷해 보일 수 있지만 약간 다릅니다.
.map() 구문은 다음과 같습니다.

Array.map(<function>)


첫 번째 방법은 배열의 모든 항목에 square(n) 함수를 적용하는 것입니다.

두 번째 방법은 <function> 함수의 결과를 배열의 모든 항목에 반환하는 이 익명square(n)을 적용하는 것입니다.

첫 번째 구문은 기능적 언어에서 일반적입니다. 두 번째는 그렇지 않습니다. 다음 섹션에서 그 이유를 살펴보겠습니다.

부분 적용



부분 적용을 바로 시작하기 전에 이번에는 곱셈을 위한 또 다른 함수를 만들어 보겠습니다.

const multiply = (a, b) => a * b;


outsquare(n) 함수와 달리 이 함수는 두 개의 매개변수를 사용합니다.

배열에 10을 곱해 봅시다. 첫 번째 구문을 사용하면 다음과 같습니다.

console.log([1, 2, 3].map(multiply(10)));
// TypeError: NaN is not a function


답답하다! multiply()는 두 개의 인수를 사용하므로 첫 번째 구문을 사용할 수 없습니다.

우리는 할 수 있습니다. 그러나 두 번째 스타일 구문을 사용하십시오.

console.log([1, 2, 3].map(n => multiply(10, n)));
// [ 10, 20, 30 ]


그리고 두 구문을 모두 사용하여 이 두 산술 함수를 함께 결합할 수도 있습니다.

console.log([1, 2, 3].map(square).map(n => multiply(10, n)));
// [ 10, 40, 90 ]


그러나 첫 번째 구문(Elm에서와 같이)을 사용하기를 원하거나 필요로 하는 경우. 그런 다음 부분 적용을 사용해야 합니다.
multiply() 함수를 리팩토링하여 부분 적용을 사용하도록 합시다.

const multiplyPartial = (a) => (b) => a * b;


당신이 나와 같은 단순한 자바스크립트 개발자라면 아마도 당신의 두뇌를 손상시키고 당신을 약간 전율하게 만들었을 것입니다.

두 개의 매개변수 대신 multiplyPartial는 두 개의 함수와 같습니다. 첫 번째 함수는 두 입력의 곱을 반환하는 다른 함수를 반환합니다.

부분 적용으로 다음과 같은 함수를 작성할 수 있습니다.

const multiplyPartial10 = multiplyPartial(10);

multiplyPartial10 함수는 이제 b 인수를 사용할 수 있으며 두 인수의 곱을 반환합니다.

multiplyPartial10(4)
// 40


우리가 얻은 오류로 돌아가서 부분 적용을 사용하여 다음을 수행할 수 있습니다.

console.log([1, 2, 3].map(multiplyPartial(10)));
// [10, 20, 30]

// or even
console.log([1, 2, 3].map(multiplyPartial10));
// [10, 20, 30]


다시 함수multiplyPartial(10)는 함수를 반환하고 해당 함수는 배열의 각 요소에 적용됩니다.

혼합 유형



JavaScript에서 매개변수가 두 가지 유형인 함수는 완벽하게 괜찮습니다.

const mixedTypesOne = (a, b) => a.toUpperCase() + " " + (b * 10);
const mixedTypesTwo = (a, b) => b.toUpperCase() + " " + (a * 10);


둘 다 다음을 제공합니다.

console.log([1, 2, 3].map(n => mixedTypesOne("This number multiplied by 10 is", n)));
console.log([1, 2, 3].map(n => mixedTypesTwo(n, "This number multiplied by 10 is")));
// [
//     'THIS NUMBER MULTIPLIED BY 10 IS 10',
//     'THIS NUMBER MULTIPLIED BY 10 IS 20',
//     'THIS NUMBER MULTIPLIED BY 10 IS 30'
// ]

mixedTypes 함수에서 어떤 유형이 먼저 오는지에 관계없이 map()의 화살표 구문을 사용하여 올바른 인수를 전달할 수 있습니다.

이제 부분 적용을 사용하여 리팩터링해 보겠습니다.

const mixedTypesPartialOne = (a) => (b) => a.toUpperCase() + " " + (b * 10);
const mixedTypesPartialTwo = (a) => (b) => b.toUpperCase() + " " + (a * 10);


첫 번째를 실행하면 다음이 제공됩니다.

console.log([1, 2, 3].map(mixedTypesPartialOne("This number multiplied by 10 is")));
// [
//     'THIS NUMBER MULTIPLIED BY 10 IS 10',
//     'THIS NUMBER MULTIPLIED BY 10 IS 20',
//     'THIS NUMBER MULTIPLIED BY 10 IS 30'
// ]


그러나 두 번째:

console.log([1, 2, 3].map(mixedTypesPartialTwo("This number multiplied by 10 is")));
// TypeError: b.toUpperCase is not a function

mixedTypesPartialTwo 에서 b로 전달된 인수는 문자열이 아니라 숫자입니다.

그래서 뭐?



위의 예에서 알 수 있듯이 파이핑 및 부분 적용은 일부 일반적인 JavaScript 사례, 즉 두 개의 매개 변수가 있는 함수와 항상 잘 작동하지 않습니다.

Elm에서 함수는 하나의 인수1만 사용하고 부분 적용이 나머지를 수행합니다.

나는 파이프 연산자에 대해 신이 나지만 코드 작성 방법에 대해 조금 다르게 생각해야 한다는 것을 의미합니다. 나는 이 개념에 약간 어려움을 겪었으므로 이것이 다른 사람들을 도울 수 있기를 바랍니다.



So conceptually, every function accepts one argument.

좋은 웹페이지 즐겨찾기