2주차 복습

map, filter, reduce

  • 보조함수를 이용하는 고차함수화를 통한 재구현
  • 이터레이터 프로토콜 다형성 지원 함수

map

const map = (f, iter) => {
  let res = []
  for (const a of iter) {
    res.push(f(a))
  }
  return res
}

// ... 사용 예시

log(map(p => p.name, products))

filter

const filter = (f, iter) => {
  let res = []
  for (const a of iter) {
    if (f(a)) res.push(a)
  }
  return res
}

// ... 사용 예시

log(filter(p => p.price < 20000, products))

reduce

const reduce = (f, acc, iter) => {
  if (!iter) {
    iter = acc[Symbol.iterator]()
    acc = iter.next().value
  }
  for (const a of iter) {
    acc = f(acc, a)
  }
  return acc
}

// ... 사용 예시

const add = (a, b) => a + b
log(reduce(add, 1, [2, 3, 4, 5]))
log(reduce(add, [1, 2, 3, 4, 5]))

map+filter+reduce 중첩 사용과 함수형 사고

  • 응용 코드 예시
const products = [
  { name: '반팔티', price: 15000 },
  { name: '긴팔티', price: 20000 },
  { name: '핸드폰케이스', price: 15000 },
  { name: '후드티', price: 30000 },
  { name: '바지', price: 25000 },
]

const add = (a, b) => a + b

log(
  reduce(
    add,
    map(
      p => p.price,
      filter(p => p.price < 20000, products)
    )
  )
)

log(
  reduce(
    add,
    filter(
      n => n >= 20000,
      map(p => p.price, products)
    )
  )
)

코드를 값으로 다루어 표현력 높이기

  • go, pipe

go

const go = (...args) => reduce((a, f) => f(a), args)

// ... 사용 예시
go(
  0,
  a => a + 1,
  a => a + 10,
  a => a + 100,
  log // 111
)
  • go 함수의 결과는 평가되는 값.

pipe

const pipe = (f, ...fs) => (...as) => go(f(...as), ...fs)

// ... 사용 예시
const f = pipe(
  (a, b) => a + b,
  a => a + 10,
  a => a + 100
)

log(f(0, 1))
  • pipe 함수의 결과는 합성된 함수
  • 내부적으로 go함수를 사용

go 함수를 사용해 읽기 좋은 코드 만들기

  • AS-IS
const add = (a, b) => a + b

log(
  reduce(
    add,
    map(
      p => p.price,
      filter(p => p.price < 20000, products)
    )
  )
)
  • TO-BE
const add = (a, b) => a + b

go(
  products,
  products => filter(p => p.price < 20000, products),
  products => map(p => p.price, products),
  prices => reduce(add, prices),
  log
)
  • 사고 순서를 뒤집었다.

go+curry를 사용하여 더 읽기 좋은 코드로 만들기

curry

  • 받아둔 함수를 내가 원하는 시점에 평가시키는 함수
const curry = f => (a, ..._) => (_.length ? f(a, ..._) : (..._) => f(a, ..._))

응용

  • map, filter, reduce 에 curry 적용하기
const map = curry((f, iter) => {
  let res = []
  for (const a of iter) {
    res.push(f(a))
  }
  return res
})

const filter = curry((f, iter) => {
  let res = []
  for (const a of iter) {
    if (f(a)) res.push(a)
  }
  return res
})

const reduce = curry((f, acc, iter) => {
  if (!iter) {
    iter = acc[Symbol.iterator]()
    acc = iter.next().value
  }
  for (const a of iter) {
    acc = f(acc, a)
  }
  return acc
})
  • TO-BE
const add = (a, b) => a + b

go(
  products,
  products => filter(p => p.price < 20000, products),
  products => map(p => p.price, products),
  prices => reduce(add, prices),
  log
)
  • TO-BE 의 TO-BE
const add = (a, b) => a + b

go(
  products,
  products => filter(p => p.price < 2000)(products),
  products => map(p => p.price)(products),
  prices => reduce(add)(prices),
  log
)

// 최종
go(
  products,
  filter(p => p.price < 2000),
  map(p => p.price),
  reduce(add),
  log
)

프론트엔드 개발자 이지원입니다.@thinkanddoit
🍎 경험주의자 입니다. 🙋🏻‍♂️ 함께 성장하는 것을 좋아합니다. 📈 꾸준히 성장하기 위한 습관을 들입니다. 🤔 프로세스 고도화에 관심이 있습니다. 🗣 스몰톡을 좋아합니다. ☕️ 커피를 좋아합니다. ⚽️ 축구를 좋아합니다.

GitHubVelogResume