Haskell 소개
Haskell 소개 (Introduction)
Haskell 2010 언어 리포트의 맨 앞장이에요. 이 장에서 언어가 무엇을 하는 언어인지, 리포트가 어떻게 구성되어 있는지, 그리고 앞으로 이어질 각 장이 무엇을 다루는지를 한눈에 보여줍니다. 코드 한 줄이 아니라 언어 전체의 윤곽부터 잡아 보는 자리예요.
본문
Haskell은 범용(汎用)의 순수 함수형 프로그래밍 언어(purely functional programming language)로서, 프로그래밍 언어 설계의 최근 혁신들을 많이 흡수한 언어예요. Haskell은 고차 함수(higher-order function), 비엄격 의미론(non-strict semantics), 정적 다형성 타입(static polymorphic typing), 사용자 정의 대수적 데이터타입(user-defined algebraic datatype), 패턴 매칭(pattern-matching), 리스트 컴프리헨션(list comprehension), 모듈 시스템(module system), 모나딕 I/O 시스템(monadic I/O system), 그리고 리스트·배열·임의 정밀도 및 고정 정밀도 정수·부동소수점 수 등 풍부한 원시 데이터타입 집합을 제공해요. Haskell은 수년간의 비엄격 함수형 언어 연구의 정점이자, 그것을 굳건하게 다져 놓은 결과물이에요.
이 리포트는 Haskell 프로그램의 문법(syntax)과, 그런 프로그램의 의미(meaning)에 대한 비형식적 추상 의미론(informal abstract semantics)을 정의해요. Haskell 프로그램을 어떻게 조작하고 해석·컴파일하는지는 구현 의존적으로(implementation dependent) 남겨 둡니다. 여기에는 프로그래밍 환경의 성격이나, 정의되지 않은 프로그램(즉 형식적으로 ⊥로 평가되는 프로그램)에 대해 돌려주는 오류 메시지 같은 문제도 포함돼요.
1.1 프로그램 구조 (Program Structure)
이 절에서는 Haskell의 추상 구문·의미 구조와, 그것이 리포트 전체 구성과 어떻게 연결되는지를 설명해요.
- 최상위에서 Haskell 프로그램은 모듈(module)들의 집합이에요. 모듈에 대한 설명은 5장에 있어요. 모듈은 네임스페이스를 통제하고 큰 프로그램에서 소프트웨어를 재사용하는 방법을 제공해요.
- 모듈의 최상위는 여러 종류의 선언(declaration)들의 모음으로 이뤄져요. 모두 4장에서 다뤄요. 선언은 일반 값, 데이터타입, 타입 클래스, fixity(결합 우선순위) 정보 같은 것들을 정의해요.
- 그 다음 낮은 층위가 식(expression)이에요. 3장에서 설명해요. 식은 값을 가리키고 정적 타입을 가지는데, 식은 Haskell 프로그래밍 "작은 단위(in the small)"의 핵심이에요.
- 가장 바닥 층위는 Haskell의 어휘 구조(lexical structure)로, 2장에서 정의해요. 어휘 구조는 텍스트 파일에서의 Haskell 프로그램의 구체적 표현을 담아요.
이 리포트는 Haskell의 구문 구조를 **상향식(bottom-up)**으로 진행해요.
위에서 언급하지 않은 장은 6장(Haskell의 표준 내장 데이터타입·클래스)과 7장(Haskell의 I/O 시설, 즉 Haskell 프로그램이 외부 세계와 어떻게 소통하는지)이에요. 그 외에도 Prelude, 구체 문법, literate programming, 파생 인스턴스(derived instances)의 명세, 대부분의 Haskell 컴파일러가 지원하는 프라그마(pragma)를 설명하는 몇몇 장이 있어요.
본문 속의 Haskell 프로그램 조각 예시는 타자기체(typewriter font)로 표기돼요:
let x = 1
z = x+y
in z+1
프로그램 조각에서 임의의 Haskell 코드를 나타내는 "구멍(holes)"은 이탤릭체로 쓰여요. 예를 들어 if e1 then e2 else e3처럼요. 일반적으로 이탤릭 이름은 기억에 도움을 주는(mnemonic) 문자예요 — e는 식(expression), d는 선언(declaration), t는 타입(type) 같은 식으로요.
1.2 Haskell 커널 (The Haskell Kernel)
Haskell은 함수형 프로그래밍에서 인기를 얻은 편리한 구문 구조들을 많이 채택했어요. 이 리포트에서 그런 **문법적 설탕(syntactic sugar)**의 의미는 더 단순한 구성으로의 번역(translation)으로 주어져요. 이런 번역을 끝까지 적용하면, 그 결과물은 우리가 **Haskell 커널(Haskell kernel)**이라 부르는 Haskell의 작은 부분집합으로 쓰인 프로그램이 돼요.
커널이 형식적으로 명시되지는 않지만, 기본적으로 직관적인 표시적 의미론(denotational semantics)을 가진 람다 계산법의 약간 설탕이 첨가된 변형이에요. 각 구문 구조가 커널로 번역되는 방식은 그 구문이 소개될 때 함께 제시돼요. 이렇게 모듈식으로 설계한 덕분에 Haskell 프로그램에 대해 추론하기 쉬워지고, 언어 구현자(implementor)에게도 유용한 지침이 돼요.
1.3 값과 타입 (Values and Types)
식(expression)은 값(value)으로 평가되며 정적 타입(static type)을 가져요. Haskell에서는 값과 타입이 섞이지 않아요. 다만 타입 시스템은 여러 종류의 사용자 정의 데이터타입을 허용하고, 전통적인 Hindley-Milner 타입 구조를 쓰는 매개변수적 다형성(parametric polymorphism)뿐 아니라, 타입 클래스를 쓰는 ad hoc 다형성, 즉 오버로딩(overloading)도 허용해요.
Haskell에서 오류(error)는 의미론적으로 ⊥("바텀, bottom")와 동등해요. 기술적으로 오류는 비종료(nontermination)와 구별할 수 없기 때문에, 언어는 오류를 감지하거나 대응하는 어떤 메커니즘도 포함하지 않아요. 다만 구현체들은 오류에 대한 유용한 정보를 제공하려 할 거예요. 3.1절을 참고해요.
1.4 네임스페이스 (Namespaces)
Haskell에는 여섯 종류의 이름이 있어요: 변수와 생성자(constructor)의 이름은 값을 가리키고, 타입 변수·타입 생성자·타입 클래스의 이름은 타입 시스템과 관련된 개체를 가리키며, 모듈 이름은 모듈을 가리켜요. 이름 짓기에는 두 가지 제약이 있어요:
- 변수와 타입 변수의 이름은 소문자나 밑줄로 시작하는 식별자예요. 나머지 네 종류의 이름은 대문자로 시작하는 식별자예요.
- 하나의 식별자는 같은 스코프 안에서 타입 생성자의 이름과 클래스의 이름으로 동시에 쓰일 수 없어요.
이것이 전부예요. 예를 들어 Int는 한 스코프 안에서 모듈·클래스·생성자의 이름을 동시에 맡아도 된답니다.
더 알아보기 (Learn more)
- 2장 어휘 구조 (Lexical Structure) — 식별자·키워드·리터럴 등 언어의 가장 낮은 층위를 다뤄요.
- 3장 식 (Expressions) — 값과 정적 타입을 갖는 식이 Haskell 프로그래밍의 심장이에요.
- 4장 선언과 바인딩 (Declarations and Bindings) — 값·데이터타입·타입 클래스를 정의하는 선언들을 봐요.