YZ ZONE

[컴퓨터 프로그램의 구조와 해석] 1.1 프로그램 짤 때 바탕이 되는것 본문

IT

[컴퓨터 프로그램의 구조와 해석] 1.1 프로그램 짤 때 바탕이 되는것

러블리YZ 2022. 1. 29. 23:09

계산 프로세스 (computational process)

:컴퓨터 속에 있는 것, 데이터라고 하는 것을 조작하면서 어떤 일을 함. 프로세스는 사람이 만든 규칙(프로그램)에 따라 움직임. 

사람 대신 머리 쓰는 일을 하고 질문에 답하기도 하고 은행에서 돈을 찾거나 공장에서 로봇을 움직여 물건을 만들어내기도함.

프로세스를 다스리는 프로그램은 마법사의 주문과도 같다.

프로그래밍 언어(programming language)

:프로그램은 여러 식으로 이루어지는데 이런 식을 적을 때 쓰는 말을 프로그래밍 언어라 함. 프로그래밍 언어는 프로세스가 할 일을 적기 위해 만든 마법과 같다. 즉 컴퓨터 프로세스를 나타낼 때 프로그래밍 언어를 쓴다.

소프트웨어 기술자라면 스스로 만든 프로세스가 맡은 일을 틀림없이 해낸다고 믿을 수 있도록 제대로 프로그램을 짤 줄 알아야 한다. 

 

자기가 설계한 시스템이 앞으로 어떻게 움직일지 정확하게 그려낼 수 있어야 하고, 생각지도 못한 문제 때문에 끔찍한 사고가 터지지 않게끔 프로그램의 얼개(구조)를 제대로 잡을 줄 알아야 전문다라 할 수 있다. 오류가 어디에 숨어 있는지 찾아낼줄 알고, 제대로 고칠 줄도 알아야 한다. 제대로 된 컴퓨터 시스템은 모듈 방식에 따라 부품 단위로 만들고 고쳐 쓸고 갈아 끼울 수 있도록 설계되어 있다. 

1.1 프로그램 짤 때 바탕이 되는것

프로그래밍 언어는 프로세스에 대한 사람의 생각을 짜임새 있게 담아내는 그릇이기도 하다. 

언어를 설명할 때에는 단순한 생각을 모아 복잡한 생각을 엮어내는 수단에 무게를 둬야한다.

-기본식 (primitive expression): 언어에서 가장 단순한 것을 나타낸다.

-엮어내는 수단(means of combination): 간단한 것을 모아 복잡한 것 (compound element)으로 만든다.

-요약하는 수단(means of abstraction): 복잡한 것에 이름을 붙여 하나로 다룰 수 있게끔 간추린다.

프로그램을 짤 때 우리는 프로시저와 데이터라는 두 가지를 쓴다.

데이터란 프로시저에 쓰려는 '물건'이고 프로시저란 데이터를 처리하는 규칙이다.

1.1.1 식

( + 137 349) 

위 식은 수에 기본 프로시저(+)를 적용한 식이다.

엮은식: 여러 식을 괄호로 묶어  리스트를 만들고 프로시저 적용을 뜻하도록 엮어놓은 식

위 식(리스트)에서 맨 왼쪽에 있는 식은 연산자(+), 나머지 식은 피연산자.

엮은식을 계산한 값은 (피연산자의 값이 되는)인자에 (연산자가 나타내는) 프로시저를 적용하여 얻는다. 

위와 같이 연산자를 피연산자 왼쪽에 두는 방식을 앞가지 쓰기(prefix notation)라고한다.

식을 깊이 겹쳐 써야 할 때 인자를 중심으로 줄을 맞추고 알맞게 들여쓰는 방식을 가지런히 쓰기(pretty-printing)이라한다.

1.1.2이름과 환경

계산물체에 이름을 붙이는 수단을 변수(variable)라고 하고 변수의 값(value)은 계산물체가 된다.

# Scheme에서 이름을 지을 때 define을 쓴다. (define 이름 값)

define은 합친 연산을 간추리는 즉 복잡한 식을 계산한 값에 알기 쉬운 이름을 붙여 쓸 수 있다.

실행기 속 어딘가에 이름-물체(name-object)의 쌍을 저장해 둔 메모리가 있고 이런 공간을 환경(environment)(=바탕환경)이라고 한다. 

1.1.3엮은식을 계산하는 방법

1. 엮은식에서 부분 식의 값을 모두 구한다.

2. 엮은식에서 맨 왼쪽에 있는 식(연산자)의 값은 프로시저가 되고 나머지 식(피연산자)의 값을 인자가 됨. 프로시저를 인자에 적용하여 엮은 식의 값을 구한다.

(*(+2(*4 6))(+3 5 7))

위와 같은 엮은식은 같은 계산 규칙으로 구해야 한다 즉 같은 절차(한 프로세스)를 여러번 되밟는 기법(되돌기 기법), (=재귀)는 나무 같은 계층 구조 물체(데이터)를 다루기 알맞은 기법이다. 이렇게 값을 위로 올려보내는 규칙을 나무꼴 어큐뮬레이션(tree accumulation)이라한다. 나무에서 연산자는 마디(node)로, 연산할 것들은 가지(branch)로 나타내며 끝마디(terminal node)에는 연산자나 수가 달려있다.

 

식 속에서 쓰는 이름이 무슨 뜻인지 결정짓는건 환경이다. 프로그램이 돌아가는 방식을 이해하는 데 문맥을 결정짓는 환경개념이 중요하다.

(define x 3)은 define이라는프로시저가 따로 있어서 이를 x와3이라는 인자에 맞추어 계산하라는 뜻(엮은식)이 아니라 x라는이름의 뜻(값)을 정하는 것이다.  이와같이 보통 계산 규칙으로는 값을 구하지 못해 계산규칙이 따로 밝혀져 있어야 하는 문법을 특별한 형태라 한다.이렇게 여러종류의 식이(식의 종류마다 다른 값을 구하는 규칙이)모여 프로그래밍 언어의 문법을 이룬다.

Lisp에서 좋은 프로그래밍 언어가 꼭 갖추어야 할 것(정리)

-수와 산술연산이 기본 데이터고 기본 프로시저

-엮은식을 겹쳐 쓰는 것이 여러 연산을 한데 묶는 수단이 됨

-이름과 값을 짝 지워 정의한 것이 모자라나마 요약하는 (간추리는)수단이 됨

1.1.4 묶음 프로시저(compound procedure)

프로시저 정의: 복잡한 연산에 이름을 붙여서 쓰는 방법. 

묶음 프로시저: 이미 있던 다른 프로시저를 하나로 묶어서 만든 프로시저.

예를 들어 (define (square x) (* x x)) 식은 square = 제곱을 나타내고 (square 21)은 21의 제곱 441이고 (square (+2 5)는 7의 제곱 49가 되며 (define (sum-of-square x y)(+(square x)(square y)))에서 sum-of-square는 x^2 + y^2을 의미함으로 (sum-of-square 3 4)는 25를 의미한다.

 

[프로시저를 정의하는 문법]

(define (<name> <formal parameters>) <body>)

  - <name> : 환경에서 프로시저를 가리키는 이름(symbol)

  - <formal parameters> : 프로시저가 받아오는 인자를 가리키기 위해서 프로시저의 몸속에서 쓰는 이름

  - <body> : 프로시저를 불러 쓸 때마다 계산할 식

 

1.1.5 맞바꿈 계산법(substitution model)으로 프로시저를 실행하는 방법

(define (f a) (sum-of-squares(+ a 1)(* a 2))) 식의 (f 5)즉 a를5라고 하면 6과 10의 제곱의 합으로 136이다.

이런 프로세스(과정)에 따라 프로시저를 맞추는 방법을 맞바꿈 계산법이라한다.

*앞의define 이용*

(define (square x) (* x x))

(define (sum-of-squares x y)

  (+ (square x) (square y)))

 

맞바꿈 계산법이 실제 실행기가 돌아가는 방법은 아니며 실제로는 갇힌환경(local environment)에 인자 이름을 넣어놓고 계산하는 방법을 사용함.

- 인자먼저 계산법(applicative order) 

LISP 실행기 적용 방식. 인자값 먼저 구하는 방법. 같은식을 여러번 되풀이 계산하는 경우가 생기지 않아 좀 더 빠름, 정의 대로 계산하는 규칙이 더 복잡함

- 정의대로 계산법(normal order)

값이 필요할 때까지 피연산자들을 계산하지 않고 미루어 두는 방법 즉 인자값을 계산하지 않고 식 자체를 인자이름(parameter)과 맞바꾸어 가다가 마지막에 기본 연산으로만 이루어진식 (더 펼치지 못하는 식)을 얻을 때 그 식의 값을 구하는 방법

'끝까지 펼친 다음에 줄이는'계산 방법

  (f 5)

  ->(sum-of-square (+ 5 1) (* 5 2))

  (+ (square (+ 5 1) (square (* 5 2))))

  (+ (* (+5 1) (+5 1)) (* (* 5 2) (*5 2))) : (+ 5 1), (* 5 2)를 두번 계산함

  (+ (* 6 6) (* 10 10))

  (+ 36 100) 

136

1.1.6 조건 식과 술어(predicate)

갈래나누기: x>0일 경우 x, x=0일 경우 0, x<0일 경우 -x (Lisp에서는 cond라는 문법을 씀)

ex) (define (abs x) (cond ((> x 0)x) ((= x 0) 0) ((< x 0) (-x))))

위의 식을 말로하면 x를 정의했을때 x>0이면 x, x=0이면 0, x<0이면 -x이다 라는 말.

 

[조건식의 문법]

(cond (<p1><e1>)

             . . .

           (<pn><en>)

cond라는 이름 뒤에는 두 식을 괄호로 묶어 놓은 절이 여러 개 오는데 두 식 가운데 첫 식을 술어라한다. 술어는 참,거짓의 답을 낸다.

 

[조건 식의 값을 구하는 방법]

:술어<p1>의 값을 구하는데 거짓이면 참이 될 때까지 계속 다음 술어<p2>의 값을 구한다.  계속 다음 술어의 값을 구하다가 참이 나오면 그 술어와 짝을 이루는 결과식 <e>의 값을 구하고 , 이 값을 전체 조건식의 값으로 삼는다. 만약 참이 없으면 식의 값을 정의할 수 없는 것이다.

 

(define (abs x)(cond ((< x 0) (-x))(else x)))

위 식은 abs라는 절대값 프로시저이고 'x가 0보다 작으면 -x,아닌면 x를 그대로 돌려준다'는 뜻. 

 

(define (abs x)(if (< x 0)(-x) x))

위의 식은 특별한 형태if를 쓴 경우이다. if는 따져 볼 경우가 둘밖에 없을 때 쓰기 좋은 문법. (< x 0)을 먼저 계산해 참이면 -x 아니면 x.

( if  식  참일때값  거짓을때값) 으로 구성된다 

 

(and <e1>...<en>)

왼쪽부터 계산해 하나라도 거짓이면 거짓, 둘 다 참이면 마지막 식의 값을 내놓음

(or <e1>...<en>)

하나라도 참이면 참이고 모두 거짓이면 마지막 신의 값을 내놓음

(not <e>)

참과 거짓 반대

1.1.7 뉴튼 법으로 제곱근 찾기

함수와 달리 프로시저는 반드시 효율성을 갖추어야 한다.

[함수와 프로시저의 중요도 차이]

-함수: 문제가 무엇인지 어떤 성질인지

-프로시저: 문제푸는 방법에 대한(명령하는) 지식 즉 그것을 어떻게 만들고 구하는지

뉴튼법(Newton method)

: 얻고자 하는 값에 가까운 값을 차례로 되풀이해서 구해 나감. 

x의 제곱근에 가까운 값y가 있을 때 y와 x/y의 평균을 구해 진짜 제곱근에 더 가까운 값을 구하는 방법.

 

Ex) 2의 제곱근을 구해보자

x=2 일때 가까운 값=y, 몫=x/y, 평균=(y+ x/y)/2가 되고

처음 가까운 값을 1이라 놓았을때 (y=1) 

[프로세스(과정)]

x=2    가까운 값.     몫.                            평균

              1             2/1                        (2+1)/2 = 1.5

             1.5         2/1.5 = 1.3333     ( 1.3333+1.5)/2=1.4167)  

. . .

 

[프로시저 (절차)]

제곱근을 얻으려는 수 x와 제곱근에 가까운 값 guess를 가지고 계산.

계산하다가 어림잡아 구한 값이 그만하면 되었다 싶으면 계산을 끝내고, 그렇지 않으면 더 가까운 값을 찾기 위해 똑같은 과정 되풀이.

 

1.1.8 블랙박스처럼 간추린 프로시저

- 프로시저 요약하기 : 작은 프로시저 여러 개를 묶어서 간추려 놓은 이름

프로그램을 여러 프로시저로 나누어 짤 때에는 실제 어떻게 계산되는지 드러나지 않도록 프로시저 속에 감추는게 중요. 그래야 필요한  프로시저를 하나하나 만들 필요 없이 다른 사람이 만든 것을 블랙박스처럼  불러 쓸 수 있다. 프로시저를 쓰는 사람은 그것이 무슨 일을 하는지만 알면 되지,  굳이 그것을 어떻게 만들었는지는 몰라도 된다.

 

-갇힌이름(local name): 프로시저의 매개변수(인자) 이름이 프로시저가 뜻하는 바에 아무런 영향을 주지 않아야 한다. 프로시저 정의에서 쓰는 매개변수(인자) 이름은 프로시저에 갇힌(local) 곧 몸 속에서만 쓰는 이름이어야 한다.

-프로시저에 인자 이름이 매인다는 뜻에서 이런 변수를 매인변수(bound variable)라 한다. 프로시저에서 매인변수의 이름 하나를 바꾸더라도 모두 똑같이 바꾸기만 하면 프로시저의 뜻은 달라지지 않음.

-자유변수(free variable): 프로시저의 정의에 매이지 않은 변수

-유효범위(scope): 매인 이름을 쓸 수 있는 식. 프로시저의 몸이 인자 이름을 볼 수 있는 넓이다.

 

안쪽 정의(intermal definition)와 블록 구조(block struckture)

- 블록구조(Block Structure) : 프로시저 정의를 겹쳐쓰는 모양. 프로시저를 안쪽에 감춰 쓰는 덕분에 프로시저 정의를 짧게 쓸 수 있음.

- lexical scoping 규칙 : 문범에 따라 변수가 보이는 넓이가 정해지는 규칙

'IT' 카테고리의 다른 글

인공지능  (0) 2023.01.20
[컴퓨터 프로그램의 구조와 해석] 1.2 프로시저와 프로세스  (0) 2022.01.30
Git? GitHub?  (0) 2022.01.18
안드로이드 스튜디오 - 네이버 지도 1.  (0) 2022.01.16
unity 설치  (0) 2022.01.15