Knowledge Map

프로그래밍 종류 본문

기타

프로그래밍 종류

2016. 6. 19. 18:04
출처 : 위키 

선언형 프로그래밍

선언형 프로그래밍은 두 가지 뜻으로 통용되고 있다.


한 정의에 따르면, 프로그램이 어떤 방법으로 해야 하는지를 나타내기보다 무엇과 같은지를 설명하는 경우에 "선언형"이라고 한다. 예를 들어, 웹 페이지는 선언형인데 웹페이지는 제목, 글꼴, 본문, 그림과 같이 "무엇"이 나타나야하는지를 묘사하는 것이지 "어떤 방법으로" 컴퓨터 화면에 페이지를 나타내야 하는지를 묘사하는 것이 아니기 때문이다. 이것은 전통적인 포트란C, 자바와 같은 명령형 프로그래밍 언어와는 다른 접근방식인데, 명령형 프로그래밍 언어는 프로그래머가 실행될 알고리즘을 명시해주어야 하는 것이다. 간단히 말하여, 명령형 프로그램은 알고리즘을 명시하고 목표는 명시하지 않는 데 반해 선언형 프로그램은 목표를 명시하고 알고리즘을 명시하지 않는 것이다.


또 다른 정의에 따르면, 프로그램이 함수형 프로그래밍 언어, 논리형 프로그래밍 언어, 혹은 제한형 프로그래밍 언어로 쓰인 경우에 "선언형"이라고 한다. 여기서 "선언형 언어"라는 것은 명령형 언어와 대비되는 이런 프로그래밍 언어들을 통칭하는 것이다.


이 두가지 정의는 서로 겹치는 부분도 있다. 특히, 제한형 프로그래밍과 논리형 프로그래밍은 필요한 해의 특성을 설명하고(무엇) 그 해를 찾는 데 사용하는 실제 알고리즘은 설명하지 않는다(어떤 방법). 그러나 대부분의 논리형과 제한형 언어들은 알고리즘을 설명할 수 있고, 상세한 부분을 구현할 수 있어서 첫 번째 정의를 따르는 엄밀한 의미의 선언형 프로그래밍 언어는 아니다.


마찬가지로, 명령형 프로그래밍 언어로 선언형으로 프로그램을 작성할 수도 있다. 라이브러리나 프레임워크 내부의 비선언형 부분을 캡슐화하여 이렇게 할 수 있다. 이런 형태의 예가 제이유닛 유닛 테스트 프레임워크에 반영되어 쓰이고 있는데, 이것은 정의만 되어 있으면 프레임워크로 등록하여 유닛을 테스트하는 것을 가능하게 한다.


선언형 프로그램에서는 그 언어의 표준 알고리즘으로 처리되는 자료 구조를 작성하거나 선언한다. 예를 들어서 웹페이지를 작성한다고 하면, 페이지가 HTML에서 무엇을 보여주어야 하는지를 선언하고 브라우저의 절차적 알고리즘이 이것을 화면에 표시할 점들로 변환한다.


선언형 언어는 다른 언어와 같이 문법을 가지고 있고 언어의 단어들이 어떻게 결합되어야 하는지 설명하고 있으며, 어떻게 프로그램의 출력에 맞게 할 것인지를 언어의 문장으로 설명하는 의미구조가 있다.



명령형 프로그래밍

컴퓨터 과학에서 명령형 프로그래밍(Imperative programming)은 선언형 프로그래밍과 반대되는 개념으로, 프로그래밍의 상태와 상태를 변경시키는 구문의 관점에서 연산을 설명하는 프로그래밍 패러다임의 일종이다. 자연 언어에서의 명령법이 어떤 동작을 할 것인지를 명령으로 표현하듯이, 명령형 프로그램은 컴퓨터가 수행할 명령들을 순서대로 써 놓은 것이다.

명령형 프로그래밍 언어는 함수형 프로그래밍이나 논리형 프로그래밍 언어와 같은 다른 형태의 언어와 다르다. 하스켈 같은 함수형 프로그래밍 언어는 구문들을 순서대로 써 놓은 것이 아니며, 명령형 프로그래밍 언어와는 다르게 전역적인 상태가 없다. 프롤로그와 같은 논리 프로그래밍 언어는 "어떻게" 계산을 할지보다는 "무엇"이 계산될 것인지를 정의한다는 생각으로 작성된다.


거의 대부분의 컴퓨터 하드웨어는 명령형으로 구현된다. 거의 모든 컴퓨터 하드웨어들이 컴퓨터의 고유 언어인 기계어를 실행하도록 설계되어 있는데, 이것이 명령형으로 씌어 있다. 낮은 수준의 관점에서 프로그램의 상태는 메모리의 내용으로 정의되고, 구문들은 기계어의 명령어로 정의된다. 높은 수준의 언어 구현은 변수와 더 복잡한 구문을 사용하지만, 여전히 같은 패러다임을 따른다. 요리법이나, 공정 점검표같은 것들은 컴퓨터 프로그램은 아니지만, 명령형 프로그래밍과 비슷한 형태의 이해하기 쉬운 개념이다. 각각의 단계의 지시 사항들이 있고, 상태라는 것은 현실 세계에 반영된다. 명령형 프로그래밍의 기본 생각이 개념적으로 친밀하고, 직접적으로 구체화되어 있어서, 대부분의 프로그래밍 언어들은 명령형이다.


보통 할당문은 메모리에 있는 정보에 연산을 수행하고, 결과값을 나중에 사용하기 위해 메모리에 저장한다. 추가로, 고급 명령형 언어는 산술 연산, 함수연산, 결과 값을 메모리에 할당하는 연산을 결합한 복잡한 수식을 계산한다. 반복문은 이런 연속된 구문을 여러번 실행하게 한다. 반복문은 미리 정의된 횟수만큼 반복하기도 하고, 어떤 조건이 바뀔때까지 반복하기도 한다. 조건 분기문은 구문의 덩어리를 어떤 조건이 만족하는 경우에만 실행하게 할 수 있다. 그렇지 않으면, 그 구문의 덩어리를 실행하지 않고 그 다음부터 실행한다. 비조건 분기문은 실행 순서를 프로그램의 다른 부분으로 옮기는 것이다. 여러 언어에서 제공하는 GOTO문, 서브프로그램, 프로시저, 호출문들이 비조건 분기문이다.



절차적 프로그래밍

절차적 프로그래밍(procedural programming)은 절차지향 프로그래밍 혹은 절차지향적 프로그래밍이라고도 불리는 프로그래밍 패러다임의 일종으로서, 때때로 명령형 프로그래밍과 동의어로 쓰이기도 하지만, 프로시저 호출의 개념을 바탕으로 하고 있는 프로그래밍 패러다임을 의미하기도 한다. 프로시저는 루틴, 하위프로그램, 서브루틴, 메서드, 함수(수학적 함수와는 다르고 함수형 프로그래밍에 있는 함수와는 비슷한 의미이다.)라고도 하는데, 간단히 말하여 수행되어야 할 연속적인 계산 과정을 포함하고 있다. 프로그램의 아무 위치에서나 프로시저를 호출될 수 있는데, 다른 프로시저에서도 호출 가능하고 심지어는 자기 자신에서도 호출 가능하다.


절차적 프로그래밍은 복잡도가 지나치지 않고 유지보수하기 쉽기 때문에 단순한 순차적 프로그래밍이나 비구조적 프로그래밍보다 여러 상황에서 장점이 많다. 다음과 같은 것들이 있다:

  • 복사해서 붙이지 않고도 같은 코드를 다른 장소에서 다시 사용할 수 있게 해 준다.
  • GOTO문이나 JUMP문을 쓰는 것보다 프로그램의 흐름을 더 쉽게 따라갈 수 있게 해준다. (GOTO문이나 JUMP문을 많이 쓰면 크고 복잡한 프로그램이 일명 스파게티 코드가 될 수도 있다.)
  • 모듈화를 하거나 구조화를 할 수 있다.


프로시저와 모듈성

크고 복잡한 프로그램을 작성할 때 모듈성은 꼭 필요하다. 모듈성은 프로시저에 어떤 형태의 입력과 출력이 이루어지는지 명확한 규칙을 정하여 구현할 수 있다. 입력은 주로 인수(인자, 매개변수)의 형태로 문법적으로 지정하고, 출력은 결과값(반환값)으로 지정한다.

유효범위(스코프)는 프로시저가 모듈성을 잘 지킬 수 있게 해 준다. 이것은 프로시저가 다른 프로시저의 변수에 접근하거나 그 반대의 경우를 막아준다. 명시적인 허가를 하지 않으면 방금전의 자기 자신의 변수에도 접근할 수 없게 된다. 유효 범위는 서로 다른 장소에서 같은 이름의 변수를 사용하여 혼동되는 것을 막아주고, 다른 프로시저의 영역을 침해하는 것을 막아준다.

모듈성이 덜한 프로시저는 빨리 만든 간단한 프로그램에서 사용되기도 하는데 실행환경에서 많은 변수들과 소통하는 경향이 있고, 다른 프로시저가 변수값을 수정할 수 있을지도 모르게 된다. 여러 변수가 프로그램의 다양한 부분들 사이에서 관계가 있다면 이것은 모듈성을 약하게 한다.

더 간단하고, 독립적이고, 다시 사용할 수 있기 때문에 프로시저는 프로그램 라이브러리를 포함하여 서로 다른 사람들이나 단체에서 작성한 코드의 조각들을 담을 수 있는 훌륭한 그릇이다.

(모듈소프트웨어 패키지 참조)

명령형 프로그래밍과의 비교

현재까지 남아있는 대부분의 절차적 프로그래밍 언어는 명령형 프로그래밍 언어이기도 한데, 이것은 실행 환경의 상태(state)로 명시적인 참조를 하기 때문이다. 이것은 변수(프로세서 레지스터에 대응될 수도 있다)로부터 시작해서 로고 프로그래밍 언어의 "거북이" 위치 같은 것(화면상의 커서부터 시작해서 방바닥 주변에 있는 장치들까지도)까지 어떤 것이든 될 수 있다.

객체지향 프로그래밍 같이, 일부 명령형 프로그래밍의 형태는 절차적이지 않은 것들도 있다.

객체지향 프로그래밍과의 비교

좀 더 최근에 나온 객체지향 프로그래밍을 통하면 좀 더 세련된 형태의 모듈화를 할 수 있다. 프로시저와 프로시저의 입력과 출력을 다루는 대신에 객체지향 프로그램들은 객체를 다룬다. 연산은 객체에게 내부 프로시저 중에 하나(혹은 상속받은 것)를 수행하라고 요청하는 것으로 이루어지며 이런 방법으로 하여 내부 상태를 다룬다. ...

절차적 프로그래밍 언어들

절차적 프로그래밍 언어들은 절차적 프로그래밍 접근 방식을 따름으로써 프로그래머의 작업을 수월하게 한다. 알골과 같은 언어가 절차적 프로그래밍 언어의 표준적인 예이다. 그 밖에 포트란, PL/I, 모듈라-2, 에이다, 베이직, C 등이 있다.




함수형 프로그래밍

함수형 프로그래밍은 자료 처리를 수학적 함수의 계산으로 취급하고 상태와 가변 데이터를 멀리하는 프로그래밍 패러다임의 하나이다. 명령형 프로그래밍에서는 상태를 바꾸는 것을 강조하는 것과는 달리, 함수형 프로그래밍은 함수의 응용을 강조한다. 함수형 프로그래밍은 1930년대에 계산가능성, 결정문제, 함수정의, 함수응용과 재귀를 연구하기 위해 개발된 형식체계인 람다 대수에 근간을 두고 있다. 다수의 함수형 프로그래밍 언어들은 람다 연산을 발전시킨 것으로 볼 수 있다.


수학적 함수와 명령형 프로그래밍에서 사용되는 함수는 차이가 있는데, 명령형의 함수는 프로그램의 상태의 값을 바꿀 수 있는 부작용이 생길 수 있다. 이 때문에 명령형 함수는 참조 투명성이 없고, 같은 코드라도 실행되는 프로그램의 상태에 따라 다른 결과값을 낼 수 있다. 반대로 함수형 코드에서는 함수의 출력값은 그 함수에 입력된 인수에만 의존하므로 인수 x에 같은 값을 넣고 함수 f를 호출하면 항상 f(x)라는 결과가 나온다. 부작용을 제거하면 프로그램의 동작을 이해하고 예측하기가 훨씬 쉽게 된다. 이것이 함수형 프로그래밍으로 개발하려는 핵심 동기중 하나이다.


Hope같은 최초의 순수 함수형 언어는 상업적 소프트웨어 개발보다는 학계에서 많은 관심을 받았다. 하지만 커먼 리스프, 스킴, ISLISP, 클로져, Racket, 얼랭, OCaml, 하스켈, 스칼라, F# 같은 주요 함수형 언어들은 광범위한 기관에서 산업적이고 상업적인 응용 프로그램 개발에 사용되고 있다. 함수형 언어는 R (통계), 매스매티카 (기호와 수론 수학), J, K 와 Kx 시스템 기반 (재정 시스템)에서 나온 Q, XQuery/XSLT (XML), Opal 같은 특정 분야 프로그래밍 언어(Domain Specific Language)에서도 사용되고 있다. 많이 쓰이는 특정 분야 선언 언어인 SQLlex/Yacc는 특히 가변값을 회피하는데 있어 함수형 언어의 요소들을 사용한다.


함수형 스타일의 프로그래밍은 함수형 언어로 별도로 설계되지 않은 언어에서도 가능하다. 예를 들어, 명령형인 프로그래밍 언어는 함수형 프로그래밍 개념을 적용하는 법을 설명하는 책에서 주제로 다루기도 했다. C# 3.0은 함수형 스타일의 쓸 수 있는 구문을 추가했다.


익명 함수

익명 함수(anonymous function)란, 이름이 없는 함수를 뜻한다. 전통적인 명령형 언어에서는 모든 함수에 이름이 부여되어야만 한다. 예컨대 인수를 제곱하는 함수를 C 언어로 작성한다면 다음과 같이 작성할 수 있을 것이다.

 int square(int x) { return x * x; }

그러나 함수형 언어에서는 이 함수를 익명함수로 작성할 수 있다.

다음은 하스켈로 작성한 제곱 함수이다.

 \x -> x * x

여기서 \x의 역빗금 \은 람다 계산법의 람다를 의미한다. 위 함수를 람다 표현으로 나타내면 가 된다.

C++11에서는 다음과 같이 작성한다.

 [](int x) -> int { return x * x; }

고계 함수[편집]

고계 함수(higher-order function)란, 함수를 다루는 함수를 뜻한다. 사실 함수형 언어에서는 함수도 '값(value)'으로 취급한다. 그러므로 정수 1이나 인수를 제곱하는 함수나 동등한 입장에서 다룰 수 있다. 정수를 함수의 인수로 전달할 수 있듯이 어떤 함수도 다른 함수의 인수로 전달할 수 있다. 마찬가지로 함수의 결과 값으로 정수를 반환할 수 있듯이 함수를 반환할 수도 있다.

예를 들어서 1에서 10까지 숫자로 이루어진 리스트의 각 원소를 제곱하고 싶다고 하자. 명령형 언어에서는 반복문을 이용하여 리스트를 훑어 가며 각 원소를 제곱하겠지만, 함수형 언어에서는 리스트를 다루는 고계 함수로 이를 처리할 수 있다. 다음은 하스켈을 이용하여 이를 수행한 예를 보여준다.

 map (\x -> x * x) [1..10]

여기서 [1..10]은 1에서 10까지 숫자로 이루어진 리스트다. 고계 함수 map은 첫 번째 인수로 주어진 함수(여기서는 제곱을 수행하는 익명함수)를 두 번째 인수로 주어진 리스트의 각 원소에 적용한 결과 리스트를 반환한다. 위 코드를 수행하면 다음과 같은 결과를 얻을 수 있다.

[1,4,9,16,25,36,49,64,81,100]


Comments