[TS] 선언형 프로그래밍과 배열

로선생·2022년 6월 7일
0

타입스크립트

목록 보기
12/14

배열은 선언형 프로그래밍을 구현할 때 절대적으로 필요한 문법 기능이다.
선언형(Declearative) 프로그래밍은 곧잘 명령형(Imperative) 프로그래밍과 비교되지만, 이 둘은 대등하게 비교할 대상은 아니다.
명령형은 저수준 구현 방식(CPU친화적)이고, 선언형은 고수준(인간 친화적) 구현 방식이다.

명령형(Imperative) 프로그래밍

프로그래밍의 기본 형태는 1)입력 데이터를 얻고 2)가공한 다음, 3)결과를 출력하는 형태로 구성된다.
명령형 프로그래밍에서는 여러 개의 데이터를 대상으로 할 때 for문을 사용해서 구현한다.

for(){
	입력 데이터 얻기
    입력 데이터 가공해 출력 데이터 생성
    출력 데이터 출력
}

선언형(Declearative) 프로그래밍

선언형 프로그래밍은 시스템 자원의 효율적인 운용보다는 일괄된 문제 해결 구조에 더 집중한다.
명령형 프로그래밍처럼 for문을 사용하지 않고 모든 데이터를 배열에 담는다. 그리고 문제가 해결될 때 까지 끊임없이 또 다른 형태의 배열로 가공하는 방식으로 구현한다.

  • 문제를 푸는 데 필요한 모든 데이터 배열에 저장
  • 입력 데이터 배열을 가공해 출력 데이터 배열 생성
  • 출력 데이터 배열에 담긴 아이템 출력

명령형 프로그래밍은 무엇을 어떻게(HOW) 할 것인가에 가깝고, 선언형 프로그래밍은 무엇을(WHAT) 할 것인가와 가깝다.

나는 지금 e마트 바로 옆에 있습니다. 그럼 여기서부터 집까지 어떻게 가야 할까요?"
명령형 방식 (HOW) : 주차장 북쪽 출구를 나와 왼쪽으로 가세요. 12번가 출구에 도착할 때까지 15번 북쪽 도로를 타세요. 이케아를 끼고 우회전하세요. 직진하여 첫 번째 신호등에서 우회전 하세요. 다음 신호등을 지나 좌회전을 하세요. 우리 집은 #298입니다.
선언형 방식 (WHAT)  : 내 주소는 98 West Immutable Alley, Eden, Utah 84310입니다.

예시 출처: https://boxfoxs.tistory.com/430

예시를 통해 차이점을 살펴보자.

1부터 100까지 더하기

1) 명령형 프로그래밍 방식

let sum = 0
for(let val = 1; val <= 100)
	sum += val++
    
console.log(sum) //5050

2) 선언형 프로그래밍 방식

const range = (from: number, to: number): number[] =>
	from < to ? [from, ...range(from+1, to): []

let numbers: number[] = range(1, 100+1)
console.log(numbers) //[1,2, ... 100]

명령형 코드는 데이터와 가공이 for 문 안에서 이루어졌지만, 선언형은 데이터 생성과 가공 과정을 분리한다.
배열에 담긴 모든 데이터를 이제 더하면 값이 나온다.
이 방식의 데이터 가공은 함수형 프로그래밍에서 흔히 만날 수 있는 '폴드'라는 함수를 사용한다.

fold: 배열 데이터 접기

폴드함수는 배열 형태의 데이터를 가공해 하나의 값을 생성할때 사용한다.
배열의 아이템 타입이 T일때, 배열은 T[]로 표현할 수 있는데, 폴드 함수는 T[]타입의 배열을 가공해 T타입 결과를 만들어준다.

export const fold = <T>(array: T[], callback: (result: T, val: T) => T, initValue: T) => {

let result: T = initValue
for(let i = 0; i< array.length; ++i){
	const value = array[i]
    result = callback(result, value)
}
return result
}

// 선언형 프로그래밍 방식에서 만들었던 함수 range
// 입력 데이터 생성
let numbers: number[] = range(1, 100+1)
//입력 데이터 가공
let result = fold(numbers, (result, value) => result+value, 0)
console.log(result) //5050

명령형 방식은 시스템 자원의 효율을 최우선으로 생각하지만, 선언형 방식은 범용으로 구현된 함수를 재사용하면서 문제를 해결한다.

1~100까지 홀수의 합 구하기

1) 명령형 방식

1에서부터 시작하여 2씩 증가시키면 홀수를 만들수 있다는 경험에 의존한다.

let oddSum = 0
for(let val=0; val=<100; val += 2)
	oddSum += val
console.log(oddSum) // 2500

2) 선언형 방식

범용적이고 재사용 가능하다는 관점에서 풀어보자.
함수형 프로그래밍에서 filter이름의 함수는 입력 배열을 가공해 조건에 맞는 값만 추려내는 기능을 한다.

export const filter = <T>(array: T[], callback: (value: T, index?: number) => boolean): T[] => {

  let result: T[] = []
  for(let index: number = 0; index< array.length; ++index){
      const value = array[index]
      if(callback(value, index))
      result = [...result, value]
}
return result
}

// 선언형 프로그래밍 방식에서 만들었던 함수 range
let numbers: number[] = range(1, 100+1)
const isOdd = (n: number): boolean => n%2 != 0

let result = fold(
	filter(numbers, isOdd),
    (result, value) => result + value, 0
)

console.log(result) //2500

사실 타입스크립트는 이러한 선언형 프로그래밍이 메서드 형태로 구현이 되어있다.
다음 장에서 계속 알아보자.

profile
이제는 이것저것 먹어요

0개의 댓글