09. Paradigms + Scripting Language
#PLT
프로그래밍 언어 패러다임 및 스크립팅 언어
프로그래밍 언어 이론 (Programming Language Theory)
목차
- 프로그래밍 언어 패러다임 개요 (PL Paradigm Overview)
- 스크립팅 언어 (Scripting Languages)
프로그래밍 언어 패러다임 (Programming Language Paradigms)
- 프로그래밍 언어가 따르는 원칙과 전략입니다.
- 예: 절차적(procedural), 명령형(imperative), 객체 지향(object-oriented, OOP), 함수형(functional), 논리형(logic) 등
- 하나의 프로그래밍 언어가 여러 패러다임을 따를 수 있습니다.
- 예: 자바(Java)는 명령형과 객체 지향 패러다임을 따릅니다.
언어 패러다임 (Language Paradigms)
- 프로그래밍 언어를 분류하는 여러 가지 방법이 있습니다.
- 명령형 (Imperative)
- 절차적 (예: Fortran, Pascal, Basic, C)
- 객체 지향 (예: Smalltalk, C++, Java)
- 스크립팅 언어 (예: Perl, Python, JavaScript)
- 선언형 (Declarative)
- 함수형 프로그래밍 (예: Scheme, ML, Haskell)
- 논리 프로그래밍 (예: Prolog, Datalog)
- 명령형 (Imperative)
명령형 언어 (Imperative Languages)
- 명령형(imperative): command or statements을 내리는 방식입니다.
- program state를 변경하기 위해 assignments을 사용합니다.
- 프로그램이 어떻게 작동하는지에 집중합니다(알고리즘).
- low level에서는, 명령어가 program state(register/memeory)를 수정합니다.
- high level에서는, program state가 variable(변수)로 표현되고, 문장(statements)은 기계 명령어로 변환됩니다.
선언형 언어 (Declarative Languages)
- 선언형 언어는 종종 비명령형(non-imperative) 언어로 정의됩니다.
- ’what to do’를 설명하며, ‘how to do’는 설명하지 않습니다.
- 뭘 할 건지만 알려주고, 어떻게 할 지는 알려주지 않는다.
명령형 접근(HOW): "저기 Gone Fishin' 이라고 적힌 표지판 아래에 있는 테이블이 비어있네요.
우리는 저기로 걸어가서 저 테이블에 앉도록 하겠습니다."
선언형 접근(WHAT): "2명 자리 주세요."
선언형은 시키기만하고, 어떻게 하라는지는 알려주지 않는다.
⠀
명령형 방식은 내가 실제로 자리에 어떻게 앉을지에 관심이 있다.
이를 위해 나는 내가 어떻게 테이블을 잡아서 자리에 앉을지에 관해, 필요한 단계들을 하나하나 나열해야 한다.
반면, 선언형 방식은 오로지 내가 무엇을 원하는지에 관심이 있다. 여기서 말한 '두 명을 위한 테이블' 처럼.
선언적 방식의 접근을 위해서는 명령형 방식으로
'어떻게 접근하는가'에 관한 내용이 먼저 추상화 되어있어야 한다
대표적인 선언적 방식이 SQL과 HTML이다.
SQL 쿼리에서 무엇을 하라고만 시키면 알아서 인덱싱하고 조회하고 정렬한다.
- 프로그램은 desired results(원하는 결과)를 설명하며, 컴퓨터가 수행할 명령을 제공하지 않습니다.
- 함수형 언어와 논리형 언어가 해당됩니다. (우리가 뒤에서 배울 내용)
- 그러나 명령형 언어와 선언형 언어의 구분은 명확하지 않습니다.
- 딱 잘라서 구분할 수 없다. 섞여있는 경우도 있다.
유클리드 알고리즘 예제 (Example: Euclidean Algorithm)
명령형 언어 예제: C++
control이 옮겨가서 gcd에서 실행된다. 상태에 따라 동작이 다름.
main()
함수부터 시작하며 일련의 명령들로 구성됩니다.- 프로그램을 단계별로 따라갈 수 있습니다.
명령형, 객체 지향 예제: Java
sout이 entry point. OOP 컨셉에 맞게 캡슐화하고 필드에 대해 연산을 수행.
main()
함수로 프로그램을 단계별로 따라갈 수 있습니다.- 명령형 특성을 가지며,
GCD
라는 클래스를 정의하고 정보를 캡슐화하여 클래스에 대해 연산을 제공합니다. - 객체 지향 특성도 포함됩니다.
선언형, 함수형 예제: Scheme
프로그래밍적으로 표현하는게 아니라 수학적 재귀적 정의를 표현하고 있다. 최대 공약수를 구한다는 수학적 정의만을 표현하고 있고, 어떻게 수행하는지는 추상화되어있다. gcd가 무엇인지만 알려주고 구하라는 것.
그리고 위에서 말했 던 것처럼 상태변경이 없다.
변수 값이 바뀌지 않고 함수 호출만 이루어진다.
함수형 언어에서는 표현식이 특정 값으로 평가된다.
위에서 gcd를 선언했지만 display(gcd 12 4)에서 명령하고 있다 명령형과 선언형을 명확히 분리할 수 없다.
gcd
함수가 무엇인지 정의할 뿐입니다.- 선언형 특성을 가지지만, 여전히 화면에 출력하는 명령을 포함하므로 명령형 특성도 존재합니다.
선언형, 함수형 예제: Scala
gcd(a ~~~): Int = Assignment
자바는 이런 스타일이지만
func(a, b) {
}
함수형 언어는 함수 이름 ~~ = {
}
마치 변수처럼 선언한다.
자바에서는 함수가 어떻게 동작하는지를 적지만, 함수형에서는 얘가 무엇을 하는지 적는다.
gcd
함수가 무엇인지 정의합니다.- 선언형이다.
- Java와 유사한 기능(GCD 객체,
main()
메서드 등)을 포함합니다.
선언형, 논리형 예제: Prolog
gcd
에 대한 facts과 rules을 설명합니다.- 선언형 특성을 가지며, 사실과 규칙을 기반으로 질문(쿼리)을 할 수 있습니다.
패러다임을 이해하는 이유 (Why do we care about paradigms?)
- 특정 패러다임을 따르는 프로그래밍 언어들은 공통된 특성을 공유하는 경우가 많습니다.
- 패러다임을 이해하면 각 언어의 특성도 더 쉽게 이해할 수 있습니다.
- 대부분의 프로그래밍 언어는 명령형 + 객체 지향 패러다임을 따르는데, 왜 다른 패러다임이 필요할까요?
- 프로그래밍 언어도 소프트웨어이므로 지속적으로 진화합니다.
- 다른 패러다임에서 유용하다고 여겨지는 기능이 향후에 도입될 수 있습니다.
새로운 패러다임 기능의 예 (Example of New Paradigm Features)
- Java 8에서 람다 표현식과 스트림 기능이 도입되었습니다.
- 동일한 기능을 구현할 때 여러 가지 옵션을 선택할 수 있습니다.
- 예를 들어, Java에서 단어를 세는 기능을 명령형 방식, 명령형 + 함수형 방식, 또는 함수형 방식으로 구현할 수 있습니다.
for문 Imperative 요소. 상태 변화와 실행 순서가 명시적이다.
람다 포현식 Functional 요소. null이면 1을 넣고 그렇지 않으면 1을 더하는 무엇을 해야하는지 표현.
forEach 함수형. 반복의 구체적인 표현은 숨겨져있다. 상태 변경과 반복의 책임이 forEach와 compute 메서드 내부로 추상화되어있다. 함수형에서는 내부 실행 순서나 상태변화는 신경쓰지 않는다. 따라서 반복, 조건문 등의 구체적인 표현이 나타나지 않는다.
스크립팅 언어 (Scripting Languages)
스크립팅 언어란 무엇인가? (What is Scripting Language?)
- 컴퓨터를 실제로 사용하는 과정에서 여러 프로그램을 결합해야 하는 경우가 많습니다.
- 예: 디렉토리 내 모든 로그 파일에서 특정 유형의 오류 메시지만 출력하기
- A: 디렉토리 내 모든 로그 파일 목록을 나열
- ex) ls -l
- B: 목록에서 각 로그 파일 읽기
- cat
- C: 특정 유형의 오류 메시지 찾기
- grep error
- D: 찾은 메시지를 특정 형식으로 출력
- echo
- | 를 이용해서 파이프라이닝을 할 수 있다.
- A: 디렉토리 내 모든 로그 파일 목록을 나열
- 예: 디렉토리 내 모든 로그 파일에서 특정 유형의 오류 메시지만 출력하기
글루 언어 (Glue Language)
- 스크립팅 언어는 종종 글루 언어(Glue Languages)라고 불립니다.
- 여러 프로그램을 결합하여 하나의 목표를 달성합니다.
- 두 가지 주요 선구자:
- 쉘/터미널(sh, bash)
- 텍스트 처리(sed, awk)
- 일반 목적 스크립팅 언어:
- Perl, Python, Ruby, PowerShell, AppleScript 등
- 웹을 위한 스크립팅 언어:
- PHP, JSP, Ruby on Rails, JavaScript, TypeScript 등
일반적인 특성 (Common Characteristics)
- 일반적으로 배치 모드(batch mode)와 대화형 모드(interactive mode)를 모두 제공합니다.
- 작성하기 쉬움 - 간단한 표현식 사용 가능
- 헬로 월드 (Hello World) 예제
공통 특성 (Common Characteristics)
- 간단한 스코핑 규칙(Simple Scoping Rules)과 선택적 선언(Optional Declarations)
- 모든 이름을 전역(global) 또는 지역(local)으로 간주하는 간단한 스코핑 규칙을 제공합니다.
- 선언이 필수적이지 않습니다.
- 예: Python에서 선언 없이 변수를 사용할 수 있습니다.
a = 10 + 3
b = a + 2
print(a, b)
int a, b;를 선언할 필요가 없다.
- 유연하고 동적인 타입 지정 (Flexible and Dynamic Typing)
- 대부분 동적 타입 검사(dynamic type checking)를 사용합니다.
- 컴파일 시에 하는게 아니라, 실행하면서 검사한다.
- 하나의 변수가 서로 다른 문맥에서 다양한 타입으로 사용될 수 있습니다.
- 예: JavaScript에서
- 대부분 동적 타입 검사(dynamic type checking)를 사용합니다.
- 패턴 매칭과 문자열 조작에 유용함 (Good for Pattern Matching and String Manipulation)
- 고수준 데이터 구조(high-level data structures) 지원
- 튜플, 리스트, 딕셔너리와 같은 데이터 구조가 포함됩니다.
- Python에서는 이러한 구조들이 기본 언어 기능으로 지원됩니다.
- C++나 Java에서는 표준 라이브러리(즉, 확장 또는 사전 구현된 라이브러리)로 지원됩니다.
문제 영역 (Problem Domains)
- 셸 스크립트 (Shell Scripts)
- 파일과 디렉토리를 조작하는 데 사용됩니다.
- 유닉스 명령어를 대화형으로 결합하여 사용합니다.
- 텍스트 처리 및 보고서 생성 (Text Processing and Report Generation)
- 패턴 매칭과 문자열 조작을 지원합니다.
- Perl(Practical Extraction and Report Language): 실용적인 데이터 추출 및 보고 언어로, 유전자 서열 분석 등 생물정보학(Bioinformatics)에서 사용됩니다.
- 수학 및 통계 (Mathematics and Statistics)
- 데이터 조작이 용이하며 간단하게 작성할 수 있습니다.
- R과 Python이 이 영역에서 많이 사용됩니다.
- Data Science
- 일반 목적 글루 언어 (General Purpose Glue Language)
- 하나의 프로그램 출력을 다른 프로그램의 입력으로 연결하거나 리다이렉트할 수 있습니다.
- 쉘 스크립트
- 확장 언어 (Extension Language)
- 스크립팅 언어는 기존 프로그램에 새로운 명령을 추가하는 등 유용한 기능을 더하는 데 사용됩니다.
- Lua: 게임 산업에서 많이 사용되며, 퀘스트, 스킬, 아이템, 몬스터 사양 등과 같은 항목을 정의합니다.
- 애드온/확장 개발에 활용됩니다.
- 웹 애플리케이션 (Web Applications)
- 서버 및 클라이언트 측 모두에서 사용됩니다.
- 자바스크립트 : 프론트/백 모두 쓴다.
Python 스코프 규칙 (Python Scope Rules)
- Python은 독특하고 흥미로운 스코프(scope) 규칙을 가지고 있습니다.
- 변수가 명시적으로 선언되지 않으면 지역(local)으로 간주됩니다.
- 블록 내에서 읽기만 하고 쓰지 않는 변수는 가장 가까운 외부 스코프에서 찾아볼 수 있습니다.
변수에 값을 assignment하는 것은 곧 선언하는거다~
outer()
함수는i
를 읽지 않고 새로운 값으로 쓰기만 합니다.j
를 읽어middle()
에 전달합니다.middle()
함수는i
와j
모두를 읽습니다.- middle에서 i, j, k를 리턴할 때, outer에서 i = 2로 지역변수 선언이 되어 있으므로 i = 2로 반환된다.
- j는 근처 scope에 없다 global
- k는 파라미터로 전달된 값
inner()
함수는 전역i
에 값을 씁니다.
과제: 오류 로그 출력하기 (Task: Print Error Logs)
- 로그 파일이 일련의 파일로 디렉토리에 저장되어 있습니다.
- 로그 파일 이름에는 날짜가 포함되어 있습니다.
- 각 파일에서 로그의 유형은 헤더로 나타납니다.
- 예:
[build]
,[error]
,[normal]
- 예:
[error]
로그만을 새로운 파일에 저장해야 합니다.
예제:
[build] build task xxx started.
[normal] /usr/local/bin/python3 ...
[error] cannot resolve dependencies...
[normal] /usr/local/bin/python3 ...
[error] failed to compile XXX.
[error] cannot execute task YYY.
[build] build task xxx completed.
과제: 오류 로그 출력하기 (Task: Print Error Logs)
- Java로 구현할 경우:
- 파일을 읽는 작업이 표준 라이브러리만 사용했을 때 불편할 수 있습니다.
- Java 7 이후로
java.nio.file.Files
를 사용할 수 있습니다. - 코드 작성 ➞ 컴파일 ➞ 실행 과정이 IDE를 사용하지 않으면 쉽지 않습니다.
- Python으로 구현할 경우:
- 필요한 코드를 몇 줄만으로 요구사항을 충족할 수 있습니다.
- REPL(Read-Eval-Print Loop)을 사용하여 필요한 코드를 더 쉽게 작성하고 실행할 수 있습니다.
- 중간 결과를 확인하고 코드 수정도 실시간으로 가능합니다.
'Programming Language > Theory' 카테고리의 다른 글
[PLT/프로그래밍언어론] 11. Functional Programming(1) (0) | 2024.12.22 |
---|---|
[PLT/프로그래밍언어론] 10. Object Oriented Paradigm (0) | 2024.12.22 |
[PLT/프로그래밍언어론] 08. 중간 정리 (0) | 2024.12.22 |
[PLT/프로그래밍언어론] 07. Control Abstraction and Data Types (0) | 2024.12.21 |
[PLT/프로그래밍언어론] 06. Control Structure (0) | 2024.12.21 |