프로그래밍 패러다임에 관한 아티클을 보다보면 "~는 선언적이라서 가독성이 좋다" 라는 표현을 종종 접하게 된다.
그런데 코드가 선언적이라는 말이 정확히 의미하는 바가 대체 뭘까?
how보다 what에 관심을 두는 것?
함수형 컴퓨팅에 쓰이는 프로그래밍 패러다임?
명령형은 뭔가 if문이 많은것 같고... 선언형은 뭔가 명료하다!?
선언형 방식으로 작성되었다는 코드를 직접 보면 무슨 느낌인지는 알겠는데... 이게 그래서 명확하게 무엇인지 말하려고 하면 정의 보다는 선언적 프로그래밍의 특징, 느낌적인 느낌...정도 만을 나열하게 된달까.
그런 의문을 품고있던 중 SICP 책에서 기술하는 선언적 지식과 명령적 지식(선언적 지식과 자주 대비되는)의 정의가 퍽 와닿았다.
명령적 지식(imperative knowledge) : 무언가를 하는 방법을 서술하는 것
선언적 지식(declarative knowledge) : 사물의 성질을 서술하는 것
사물의 성질 <- 이 표현이 마음에든다. 확실히 '무엇(what)을 할지 서술하는것'... 이라는 표현보다는 명확하다.
이 두 개념의 차이를 잘 이해하기 위해서 제곱근을 구하는 문제를 생각해보자.
제곱근 함수는 다음과 같이 정의할 수 있다.
√x = y ≥ 0 이고 y² = x 라는 조건을 충족하는 y
이 문장은 제곱근을 정확하게 정의한다. 하지만 그래서 도대체 실제로 y를 어떻게 구할것 인지는 말해주지 않는다.
가령, 1부터 숫자를 1씩 올려가면서 제곱해서 x와 비교해본다던지.. 수학교과서 맨뒷장에 있는 제곱근표(요즘도 이거 있나..?라떼는..)를 확인한다던지.. 실제로 구하는 방법은 알수 없다.
즉, 제곱근의 성질(선언적)을 서술하지만 제곱근을 구하는 방법(명령적)을 서술하지 않는다.
제곱근을 구하는 방법, 즉 명령적 서술과 코드는 다음과 같이 추정해서 작성할 수 있다.
제곱근을 구하는 방법
1. x의 제곱근이 될 만한 y의 값의 추정치를 정한다.
2. y² 과 x의 차를 구하여 임의로 설정한 오차범위를 벗어나는지 확인한다.
3-1. 오차범위를 벗어남 - y와 x/y의 평균으로 더 나은 추측값을 설정하여 1번부터 반복한다.
3-2. 오차범위 안에 있음 - y를 return 한다.
이 제곱근 알고리즘은 뉴턴 방법의 한 특수 사례이다. 일반적인 뉴턴 방식에서는 x - g(x)/Dg(x) 의 고정점을 찾는 방법을 반복해서 근삿값을 구한다.
코드
function sqrt_iter(guess, x) {
return is_good_enough(guess, x)
? guess
: sqrt_iter(improve(guess, x), x);
}
function improve(guess, x) {
return average(guess, x / guess);
}
function average(x, y) {
return (x + y) / 2;
}
function is_good_enough(guess, x){
return Math.abs(guess ** 2 - x) < 0.001; // 오차범위를 0.001로 설정
}
function sqrt(x) {
return sqrt_iter(1, x); // 초기 추측값을 1로 설정
}
console.log(sqrt(2)); // 1.4142156862745097
'프로그래밍 > SICP' 카테고리의 다른 글
닫힘 성질을 충족하는 데이터 구조 설계(1) (0) | 2024.02.24 |
---|---|
거듭제곱, 최대공약수, 소수판정 최적화 (+ 확률에 의한 판정) (0) | 2024.02.20 |
고차함수를 이용한 추상화 (0) | 2024.02.15 |
꼬리재귀(tail-recursion)와 꼬리 호출 최적화(TCO) (0) | 2024.02.01 |
프로그래밍 언어의 기본 요소 (0) | 2024.01.30 |