타입스크립트 기초 - 14

Stulta Amiko·2022년 7월 13일
0

타입스크립트 기초

목록 보기
14/24
post-thumbnail

람다 라이브러리

람다 라이브러리에는 여러 함수들이 존재한다.
앞에서 다뤘던 range함수라던지 디버깅할때 사용하는 tap함수라던지
다양한 함수를 제공하는 라이브러리이다.

람다 라이브러리에서 import 한후에 사용하는 방법은 이전과 같다.

import * as R from 'ramda'

console.log(
    R.range(1,10)
)

사용하는 방법은 위와같이 간단하게 사용할 수 있다.

import * as R from 'ramda'

const numbers: number[] = R.range(1,10)

R.tap(n => console.log(n))(numbers)

tap함수는 위와같은 형태로 사용하며 2차고차함수 형태이다.

전에 배웠던 compose와 pipe 함수도 람다라이브러리 내부에서 구현되어있는데

import * as R from 'ramda'

const numbers: number[] = R.range(1,10)

R.pipe(R.tap(n => console.log(n)))(numbers)

사용하는 방법은 위와 같이 별로 특별한점은없다.

pointless function

람다 라이브러리의 많은 함수들은 대부분 2차고차함수의 형태로 구현되어 있다.

import * as R from 'ramda'

const dump = R.pipe(R.tap(n => console.log(n)))

dump(R.range(1,10))

dump 함수는 pointless function의 형태를 띄고있다.

pointless 함수의 형태를 원하지 않아서 만약 일반적인 화살표함수의 형태로 만들게 된다면 오류가 발생하게 될것이다.

const dump = <T>(array: T[]): T[] => R.pipe(
    R.tap(n => console.log(n))
)(array) 

이런식으로만 하게된다면 오류가 발생한다.

const dump = <T>(array: T[]): T[] => R.pipe(
    R.tap(n => console.log(n))
)(array) as T[]

자동커리

import * as R from 'ramda'

console.log(
    R.add(1,2),
    R.add(1)(2)
)

위 코드에서 두함수는 동일하게 3을 출력한다.
람다 라이브러이의 함수들은 배개변수가 두개인 일반함수처럼 사용할 수도 있고
2차 고차함수처럼 이용할 수도 있다. 이를 람다라이브러리에서는 자동 커리라고 한다.

curryN 함수

import * as R from 'ramda'

const sum = (...numbers: number[]): number =>
    numbers.reduce((result: number,sum: number) => result+sum ,0)

const curriedSum = R.curryN(4,sum)

console.log(
    curriedSum(1),
    curriedSum(1)(2)(3)(4)
)

위와같은 형태로 사용하는 curryN 함수가 있다.

N개의 커리를 매개변수로 가지는 N차 고차함수로 만들어주는 함수가 curryN함수이다.

curriedSum 함수를 만들때 curryN의 파라미터로 number와 함수를 넣었는데 처음 파라미터가 N이고 두번째 파라미터는 고차함수의 대상이되는 함수를 만드는 것이다.

순수함수

람다라이브러리 내부의 함수들은 순수함수를 고려해 설계되었기 때문에 입력변수의 상태를 변화시키지 않고 새로운값을 반환시킨다.

import * as R from 'ramda'

const originalArray: number[] = [1,2,3]
const resultArray = R.pipe(
    R.map(R.add(1))
)(originalArray)

console.log(originalArray,resultArray)

실행결과
[1,2,3][2,3,4]

위와같은 함수를 보면 자신의 모습을 그대로 유지한채로 새로운 배열에만 값의 변화가 가는것을 볼 수 있다.
처음에 생각없이보고 당연한거 아닌가? 싶었는데 얕은복사 깊은복사를 생각해보면 꼭 당연한것만은 아니다.

배열에 담긴 수 다루기

import * as R from 'ramda'

const numbers: number[] = R.range(1,10)

const incNumbers = R.pipe(
    R.tap(a => console.log('before inc:',a)),
    R.map(R.inc),
    R.tap(a=> console.log('after inc:',a))
)

const newNumbers = incNumbers(numbers)

디버깅 함수를 이용해서 변환전과 변환후의 배열을 출력하는 코드이다.
R.pipe 내부에서는 console.log를 사용할 수 없기 때문에 tap함수를 사용해야 한다.

사칙연산 함수

import * as R from 'ramda'

const incNumber = R.pipe(
    R.map(R.add(1)),
    R.tap(a => console.log('after add(1):',a))
)

const newNumber = incNumber(R.range(1,10))

다음은 add 함수를 이용하는 코드이다.
pointless 함수와 익명함수로만 구현했기 때문에 엄청 간결하게 보이지만

pointless 함수자체 개념이 아직 어색하긴 하다
너무많이 생략해서 그런지.. 아직은 어색하지만 익숙해지려고 노력하는 중이다.

위코드는 보다시피 range로 1부터 9까지의 배열을 incNumber함수에 넣어서 돌리는 방식이다 tap함수가 출력을 해주는 방식인데 너무 간결하게 보인다.

결과는 뻔하겠지만 2부터 10까지의 수가 출력된다.

addIndex 함수

Array.map은 두번째 매개변수로 index를 제공하지만 R.map에서는 index를 기본제공하지 않는다. 따라서 Array.map처럼 동작하게 하려면 R.addIndex함수를 이용해서 R.map이 index를 제공하는 새로운 함수를 만들어야한다.

import * as R from 'ramda'

const addIndex = R.pipe(
    R.addIndex(R.map)(R.add),
    R.tap(a=>console.log(a))
)

const newNubmer = addIndex(R.range(1,10))

실행결과
[1,3,5,7,9,11,13,15,17]

배열의 인덱스를 제공해 줘서 계산하는 방식이다.
첫번째 부터보면 0+1,1+2,2+3,3+4,.....,8+9
이런식으로 계산을 하게되는것이다.

flip 함수

flip함수는 2차고차함수의 매개변수 순서를 바꿔준다.

import * as R from 'ramda'

const reserveSubtract = R.flip(R.subtract)

const newArray = R.pipe(
    R.map(reserveSubtract(10)),
    R.tap(a => console.log(a))
)(R.range(1,10))

위 함수는 value - 10 연산을 하는 함수이다.
둘의 위치가 바뀌었기 때문에 value - 10 이 되는것이다.

지금까지 하면서 이해가 안됐던 부분들이 여러 부분 있었다.
다음에는 지금까지 공부해오면서 중요했다고 생각하는 부분들을 다시 복습하는 계기를 가져야겠다.

0개의 댓글