함수형 프로그래밍에서 boolean 타입 값을 반환해 어떤 조건을 만족하는지를 판단하는 함수를 서술자라고 한다.
람다 라이브러리 내부에는 수를 비교해 boolean 타입으로 반환하는 서술자들을 제공한다.
import * as R from 'ramda'
R.lt(a)(b): boolean // a < b 이면 true
R.lte(a)(b): boolean // a <= b 이면 true
R.gt(a)(b): boolean // a > b 이면 true
R.gte(a)(b): boolean // a >= b 이면 true
수의 크기를 판단하는 서술자는 위와 같은 형식으로 제공한다.
filter 함수와 결합해서 사용하는 예제코드를 보면 다음과 같다.
import * as R from 'ramda'
R.pipe(
R.filter(R.lte(3)),
R.tap(n => console.log(n))
)(R.range(1,11))
위 코드를 읽어보면 알겠지만
결과는 3부터 10까지 출력하게 된다.
필터에서 true인 결과만 저장하게 되니깐 3보다 작을땐 전부 false를 출력하게 될것이고 이에따라 3이상의 수만 저장되게 된다.
import * as R from 'ramda'
R.pipe(
R.filter(R.lte(3)),
R.filter(R.gt(7)),
R.tap(n => console.log(n))
)(R.range(1,11))
위 코드는 3 <= x < 7을 구현한 코드이다.
위 코드를 출력하게되면 3보다 크고 7보다 작은 수가 출력되게 될것이다.
allPass/anyPass
allPass(서술자) // 배열의 조건을 모두 만족하면 true
anyPass(서술자) // 배열의 조건을 하나라도 만족하면 true
import * as R from 'ramda'
type NumberToBooleanFunc = (n: number) => boolean
const selectRange = (min: number,max: number): NumberToBooleanFunc =>
R.allPass(
[R.lte(min),
R.gt(max)]
)
R.pipe(
R.filter(selectRange(3,9)),
R.tap(n => console.log(n))
)(R.range(1,11))
위 코드는 allPass를 응용해서 3 <= x < 9를 구현한 모습이다.
not / ifElse
not 함수는 true이면 false를 반환하고 false이면 true를 반환하는 함수이다.
!연산자와 유사한 느낌인거같다.
위에서 구현한 selectRange 함수와 반대되는 함수를 쉽게 구현할 수 있다.
import * as R from 'ramda'
type NumberToBooleanFunc = (n: number) => boolean
const selectRange = (min: number,max: number): NumberToBooleanFunc =>
R.allPass(
[R.lte(min),
R.gt(max)]
)
const notRange = (min: number,max: number) => R.pipe(selectRange(min,max),R.not)
R.pipe(
R.filter(notRange(3,9)),
R.tap(n => console.log(n))
)(R.range(1,11))
기존의 selectRange를 이용하면서 이런식으로 구현이 가능하다.
위 함수는 1부터 10까지 기존의 selectRange(3,9)에 해당되었던 값의 정반대인 값을 출력한다.
기존이 다음과 같은 식을 구현했다면 3 <= x < 9
위에서 구현한 코드는 x < 3 and x >= 9
range 배열 내에서 저 조건문에 맞는 수를 남기게 된다.
ifElse는 세가지 매개변수를 포함한다.
R.ifElse(
조건서술자,
true일때 실행하는 함수,
false일때 실행하는 함수
)
위와 같은 형식으로 구성된다.
import * as R from 'ramda'
const input: number[] = R.range(1,11), halfValue = input[input.length/2]
const suborAdd = R.pipe(
R.map(R.ifElse(
R.lte(halfValue),
R.inc,
R.dec
)),
R.tap(n => console.log(n))
)
const result = suborAdd(input)
ifElse를 응용하는 코드로 하프밸류보다 작으면 1씩 빼고
하프밸류보다 크면 1씩 추가하는 코드를 가져왔다.
첫번째 파라미터의 값에 부합하는 애들은 1씩 빼주고 값에 부합하지 않는애들은 1씩 더해주는 코드이다.
이처럼 간결하게 작업을 수행할 수 있는 함수들이 람다라이브러리에 존재한다.
trim
trim은 문자열 앞뒤의 공백을 제거해준다.
import * as R from 'ramda'
console.log(
R.trim('\t hello \t')
)
toLower / toUpper
이름만봐도 알 수 있듯이 대문자로 혹은 소문자로 바꿔주는 함수이다.
import * as R from 'ramda'
console.log(
R.toUpper('hello'),
R.toLower('HELLO')
)
R.split 함수는 구분자를 사용해서 문자열을 배열로 바꿔준다.
R.join함수는 문자열 배열을 문자열로 바꿔준다.
import * as R from 'ramda'
const words: string[] = R.split(' ')(`Hello World!, I'm Peter`)
console.log(words)
위 코드를 출력하면 문자열을 배열로 만들어준다. 구분자는 ' ' 이다.
실행결과
[ 'Hello', 'World!,', "I'm", 'Peter' ]
import * as R from 'ramda'
type StringToStringFunc = (string) => string
const toCamelCase = (delim: string): StringToStringFunc =>{
const makeFirstToCapital = (word: string) =>{
const characters = word.split('')
return characters.map((c,index) => index == 0 ? c.toUpperCase() : c).join('')
}
const indexedMap = R.addIndex(R.map)
return R.pipe(
R.trim,
R.split(delim),
R.map(R.toLower),
indexedMap((value: string,index: number) => index > 0 ? makeFirstToCapital(value):value
),
//@ts-ignore
R.join('')
) as StringToStringFunc
}
console.log(
toCamelCase(' ')('Hello World'),
toCamelCase('_')('Hello_Albert')
)
위와같은 방식으로 만든다. CamelCase가 뭔가하면 이제 이름을 지을때 규칙같은것이다.
첫문자는 소문자로 그리고 띄워쓰기를 할 공간에 대문자 문자를 넣는것이다.
위 코드는 다음에 한번 더 해석해보는걸로 해야겠다.