[TIL] 내일 수정할 거 있음

JISU·2021년 12월 2일
0

TIL

목록 보기
12/27

오늘 배운 것

개발 용어

함수형 프로그래밍

조금 조사를 해보니, 아직 객체지향에 대한 이해도 제대로 못했는데 벌써 함수형 프로그래밍을 깨닫겠다고 알아보는 것은 어불성설이라고 생각되었다. (함수형 프로그래밍을 이해하려면 거의 패러다임을 바꿔야 하는 수준이라고 한다.)

대신 그만큼 깨닫고 나면 굉장히 좋고, 코드의 가독성, 국소적인 오류범위 등 장점이 많기 때문에 예상치 못한 에러의 대항마로써 (최근에는 또, 블록체인 기술 등으로 오류가 더더욱 나면 안되는) 각광을 받고 있다고 한다.

그래서 일단 가볍게 피상적인 개념만 알아보고, 순수 함수가 도대체 무엇인지만 알아보도록 한다.

객체 지향처럼 각자 뭘 만들어내서 그것을 구조적으로 잘 돌아가게 하는 것이라면
함수형 프로그래밍은 함수 자체에서는 밖이 어떻게 돌아가는지 말든지 신경쓰지 않고,
그냥 오는 것(인자)를 가지고 자기 할 일만 해서 값을 반환해주는 것만 하면 된다.
그런 함수들을 조합하고 이용해서 1을 넣었을 때 항상 "결과물" 이라는 string 값을 보장받도록 하는 것이다.

함수형 프로그래밍을 하는 원칙

  • 입출력이 순수해야한다. (순수함수여야 한다.)
  • 부작용(부산물)이 없어야 한다.
  • 불변성

이 이외에도 깊은 내용이 더 있지만, 순수함수와 불변성에 대해서만 알아보도록 한다.

  1. 순수 함수
    이 얘기는 함수형 프로그래밍에서
    함수는 항상 값을 받고 결과물을 돌려주어야 하며
    인자로 받은 값 이외에 외부 변수를 참조하거나 사용해서는 안된다는 것이다.
    받은 인자 값으로만 계산을 하기 때문에 특정 값을 넣어주면 항상 같은 값의 결과를 보장받을 수 있다는 것이다.
    그러므로 두번째 말한 것처럼 부작용이 없는 것이다.

    자바스크립트는 함수형 프로그래밍을 최대한 비슷하게 구현할 수는 있지만, this를 사용해야하는 상황이 있기 때문에 100% 함수형 프로그래밍을 할 수는 없다.

우리가 사용하고 있는 자바스크립트에서 제공하는 array method 또한 순수 함수들이다.
map, filter, reduce

  • 예제1
let arr = [1, 2, 3, 4, 5]

let doubledArr = arr.map((x) => x * 2)
console.log(arr) // [ 1, 2, 3, 4, 5 ]
console.log(doubledArr) // [ 2, 4, 6, 8, 10 ]

arr도 변하지 않고 (원본을 건드리지 않고)
map 함수는 같은 값을 넣어주면 항상 같은 값을 뱉어준다.

  • 예제2
let arr = [1, 2, 3, 4, 5]

let evenCondition = (x) => x % 2 === 0
let evenFilter = (arr) => arr.filter(evenCondition)
console.log(evenFilter(arr)) // [ 2, 4 ]

순수 함수가 아니다.
지금은 순수 함수처럼 동작할 수는 있다.
그러나 evenCondition 자체가 외부 변수(언제든지 변할 수 있는 변수)이므로
해당 구현은 순수 함수로 구현한 것이 아니다.

아래와 같이 순수함수로 구현할 수 있다.

let evenFilterPure = (array, condition) => array.filter(condition)
console.log(evenFilterPure(arr, evenCondition))

condition 자체를 인자 값으로 받았기 때문에
condition에 따라 당연히 값은 바뀐다
하지만 같은 condition을 넣게 되면 항상 같은 값을 보장 받을 수 있기 때문에
이 구현은 순수 함수로 구현되었다고 말할 수 있다.
이렇게 되면 에러를 더 쉽게 찾을 수 있는 것이다.
특정 인자를 넣었을 때, 원하는 결과물이 아니라면 값을 이것저것 넣어보면서 테스트해보고,
이상 있으면 함수 문제가 되며
이상이 없으면 인자에 문제가 있는 것으로 생각할 수 있기 때문에 디버깅 측면에서 더 좋은 것이다.

  • 예제3
    함수형 프로그래밍에서는 보통 반복문을 사용하지 말라라고 이야기한다고 한다..(명령형 패턴이기 떄문..?)아무튼 그렇기 때문에 재귀함수를 이용하여 반복을 나타내게 된다.
// 1부터 10까지 더하기 구현
// 보통
let sum = 0
for (let i = 1; i <= 10; i++) {
  sum += i
}
console.log(sum) // 55

// 순수함수 (재귀함수 이용)
const addOnetoTen = (sum, count) => {
  sum += count
  if (count > 0) {
    return addOnetoTen(sum, count - 1)
  } else {
    return sum
  }
}
console.log(addOnetoTen(0, 10)) // 55

이렇게 구현하면 코드의 재사용성이 매우 높아진다.
1부터 10을 더하는 것이 아니라 확장해서 사용 가능하다.
그리고 0, 10을 인자로 주었을 때의 값은 항상 55로 동일하다.

-예제4
순수하지 않습니다 (반환값 없이 부가 효과를 이용하고 있습니다)

let arr = ["calzon", "pajita"]
function addTaco(array) {
  array.push("taco")
}
addTaco(arr)
console.log(arr)

그냥 array.push('taco')를 실행하는 라인만 따로 빼서 함수를 정의한 것이지
함수형 프로그래밍을 한 것이 아니다.

순수하지 않습니다 (인자 대신 공유 변수를 이용하고 있습니다)

let globalArray = ["calzon", "pajita"]
function addTaco() {
  return [...globalArray, "taco"]
}
addTaco()
console.log(globalArray)

순수합니다

let arr = ["calzon", "pajita"]
function addTaco(array) {
  return [...array, "taco"]
}

console.log(addTaco(arr))

특정 배열을 넣으면 항상 taco라는 string 요소를 추가해서
배열을 반환해주는 순수 함수
원본 또한 보존하였다. + 불변성

  1. 불변성
    선언된 변수/상수를 마음대로 바꾸면 안되고,
    바꾸고 싶을 떄는 변수를 하나 더 생성해서 원본을 복사해서 사용해야 한다.

// mutable
const bands = ["Metallica", "Queen"]
bands.push("Nirvana")

// immutable
const someBands = ["Metallica", "Queen"]
const bands = [...someBands, "Nirvana"]

사실 모든 함수가 순수할 수는 없다.
I/O 작업, 난수 처리(random), 네트워킹(server에 요청), 데이터베이스 등을 처리 할 때는 본질적으로 순수할 수 없다.
그럼에도 불구하고 함수가 다룰 수 있는 영역을 더 넓게 하고,
핵심을 간단하게 유지하기 위해 이러한 컨셉은 소프트웨어의 전반에 걸쳐 적용되어야 한다.

[참고 및 출처]
https://blog.ull.im/engineering/2019/04/07/functional-programming-with-javascript-in-3-steps.html
https://soojae.tistory.com/29
https://www.zerocho.com/category/JavaScript/post/576cafb45eb04d4c1aa35078

https://velog.io/@xpmxf4/%EC%95%84%EC%9D%B4%EB%94%94%EC%97%90-%EA%B3%A0%EC%9C%A0-%EA%B0%92-%EC%A3%BC%EA%B8%B0

https://one-it.tistory.com/entry/%EB%B2%88%EC%97%AD-%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%97%90%EC%84%9C-%ED%94%BC%ED%95%B4%EC%95%BC-%ED%95%A0-%EC%95%88%ED%8B%B0%ED%8C%A8%ED%84%B4

profile
블로그 이전

0개의 댓글