위대한 선을 위한 하스켈 배우기!

ko생성일: 2025. 9. 19.갱신일: 2025. 9. 24.

하스켈이 무엇인지(순수 함수형, 지연 평가, 정적 타입과 타입 추론), 하스켈을 배울 때의 마음가짐과 GHC/GHCi로 시작하는 방법을 소개합니다.

소개

이 튜토리얼에 대하여

_위대한 선을 위한 하스켈 배우기_에 오신 걸 환영해요! 이 글을 읽고 있다면, 아마 하스켈을 배우고 싶어서 오셨겠죠. 잘 찾아오셨어요. 다만 그 전에 이 튜토리얼에 대해 잠깐 이야기해 볼게요.

제가 이 글을 쓰기로 한 이유는 제 하스켈 지식을 굳히고 싶었고, 또 제 관점에서 하스켈을 처음 접하는 분들에게 도움이 될 수 있겠다 싶었기 때문이에요. 인터넷에는 하스켈 튜토리얼이 꽤 많아요. 저도 처음에 하스켈을 배울 때 하나의 자료만으로 배우지 않았어요. 여러 튜토리얼과 글을 같이 읽었는데, 각 자료가 서로 다른 방식으로 설명하더라고요. 여러 자료를 훑어보니 퍼즐 조각이 맞춰지듯 딱 이해가 됐죠. 그래서 이 글도 여러분이 마음에 들어 하는 자료를 찾을 확률을 조금이라도 높여 보려는, 또 하나의 유용한 자료가 되려는 시도예요.

이미지 1: 새

이 튜토리얼은 명령형 프로그래밍 언어(C, C++, Java, Python …) 경험은 있지만 함수형 언어(Haskell, ML, OCaml …)는 처음인 분들을 대상으로 해요. 물론 프로그래밍 경험이 많지 않아도, 여러분처럼 똑똑한 분이라면 충분히 따라오며 하스켈을 배울 수 있을 거예요.

Libera.Chat 네트워크의 #haskell 채널은 막히는 부분이 있을 때 질문하기에 아주 좋은 곳이에요. 그곳 사람들은 초심자에게도 정말 친절하고 인내심이 많고 이해심이 넓어요.

저는 하스켈을 이해하기까지 두 번쯤은 실패했어요. 너무 낯설게 느껴져서 손에 안 잡히더라고요. 그런데 어느 순간 ‘탁’ 하고 감이 오고, 그 초기 허들만 넘기고 나니 이후로는 순항이었어요. 결국 하고 싶은 말은 이거예요: 하스켈은 훌륭하고, 프로그래밍에 관심이 있다면 처음엔 좀 이상해 보여도 꼭 배워 보세요. 하스켈을 배우는 건 처음으로 프로그래밍을 배울 때와 아주 비슷해요 — 재미있거든요! 다르게 생각하도록 만들어 주죠. 그럼 다음 섹션으로 넘어가 볼까요 …

하스켈은 뭔가요?

이미지 2: fx 하스켈은 _순수 함수형 프로그래밍 언어_예요. 명령형 언어에서는 컴퓨터에 할 일의 순서를 지시하고, 컴퓨터는 그걸 차례로 수행해요. 수행하는 동안 상태가 바뀔 수 있죠. 예를 들어 변수 a를 5로 설정했다가, 뭔가를 한 뒤 다시 다른 값으로 바꾸곤 해요. 어떤 동작을 여러 번 수행하기 위한 제어 흐름 구조도 있죠. 반면 순수 함수형 프로그래밍에서는 컴퓨터에게 무엇을 어떻게 하라고 지시하기보다, 대상이 무엇인지(정의)를 말해 줘요. 예를 들어 어떤 수의 팩토리얼은 1부터 그 수까지의 곱이고, 숫자 리스트의 합은 첫 번째 숫자에 나머지 숫자들의 합을 더한 것이죠. 이런 걸 함수의 형태로 표현해요. 또 변수를 어떤 값으로 설정해 놓고 나중에 다른 값으로 바꿀 수 없어요. a가 5라고 말했으면, 나중에 그게 다른 값이라고 말할 수 없죠. 뭐죠, 거짓말쟁이라도 되려고요? 그래서 순수 함수형 언어에서 함수는 부수효과가 없어요. 함수가 할 수 있는 일은 어떤 값을 계산해서 결과로 돌려주는 것뿐이에요. 처음엔 다소 제한적으로 보일 수 있지만, 이는 아주 멋진 결과를 가져와요: 같은 인자로 함수를 두 번 호출하면 항상 같은 결과가 보장돼요. 이를 _참조 투명성_이라고 하고, 이는 컴파일러가 프로그램의 동작을 추론할 수 있게 해 줄 뿐 아니라, 여러분이 함수가 올바름을 쉽게 유추(심지어 증명)하고, 간단한 함수들을 이어 붙여 더 복잡한 함수를 구축할 수 있게 해 줘요.

이미지 3: lazy 하스켈은 _게으르죠(지연 평가)_를 해요. 즉 특별히 지시하지 않는 한, 진짜로 결과를 보여 줘야 할 때까지 함수 실행과 계산을 미루어요. 이는 참조 투명성과 잘 맞아떨어지며, 프로그램을 데이터에 대한 _변환들의 연속_으로 생각할 수 있게 해 줘요. 무한한 자료구조 같은 멋진 것들도 가능하게 하죠. 예를 들어 xs = [1,2,3,4,5,6,7,8] 같은 불변 숫자 리스트와, 각 원소를 2배로 만들어 새 리스트를 돌려주는 doubleMe라는 함수가 있다고 해 봐요. 명령형 언어에서 리스트의 값을 8배로 만들려고 doubleMe(doubleMe(doubleMe(xs)))처럼 했다면, 아마 리스트를 한 번 훑으며 복사해서 반환하고, 또 두 번 더 훑은 뒤에야 결과를 돌려줄 거예요. 하지만 게으른 언어에서는, 결과를 강제로 요구하지 않은 채 리스트에 doubleMe를 적용하면 프로그램은 마치 “알았어, 나중에 할게!”라고 말하는 셈이 돼요. 그런데 여러분이 결과를 보고 싶어지는 순간, 첫 번째 doubleMe가 두 번째에게 ‘지금 결과가 필요해!’라고 말하죠. 두 번째는 세 번째에게 그렇게 요구하고, 세 번째는 마지못해 1을 두 배로 만든 2를 건네줘요. 두 번째는 그걸 받아 4를 첫 번째에게 주고, 첫 번째는 그걸 보고 여러분에게 첫 번째 원소가 8이라고 알려줘요. 결국 정말 필요할 때 리스트를 단 한 번만 훑게 되죠. 이렇게 게으른 언어에서는 초기 데이터만 잡고서, 필요할 때마다 효율적으로 변환하고 이어 붙이며 최종적으로 원하는 모양을 만들어 낼 수 있어요.

이미지 4: boat 하스켈은 정적 타입 언어예요. 프로그램을 컴파일할 때, 컴파일러는 어떤 코드 조각이 숫자인지, 문자열인지 등을 알고 있어요. 즉 많은 잠재적 오류가 컴파일 시점에 잡힌다는 뜻이죠. 숫자와 문자열을 더하려고 하면 컴파일러가 불평(오류)을 쏟아낼 거예요. 하스켈은 _타입 추론_을 갖춘 아주 훌륭한 타입 시스템을 사용해요. 즉 모든 코드에 타입을 일일이 달 필요가 없고, 타입 시스템이 많은 걸 똑똑하게 추론해 줘요. a = 5 + 4라고만 써도 a가 숫자라는 걸 하스켈이 스스로 알아내죠. 타입 추론 덕분에 코드가 더 일반적으로 쓸 수 있게 되기도 해요. 예를 들어 여러분이 두 인자를 받아 더하는 함수를 만들었는데 타입을 명시하지 않았다면, 그 함수는 ‘숫자처럼 동작하는’ 어떤 두 인자에도 똑같이 동작해요.

하스켈은 _우아하고 간결_해요. 고수준 개념을 많이 사용하기 때문에, 하스켈 프로그램은 보통 동등한 명령형 프로그램보다 짧아요. 그리고 짧은 프로그램은 긴 프로그램보다 유지보수가 쉽고 버그도 적죠.

하스켈은 정말 똑똑한 사람들(박사 학위 소지자들)이 만들었어요. 하스켈 작업은 1987년에 연구자들이 모여 끝내주는 언어를 설계하겠다고 시작되었죠. 2003년에는 언어의 안정된 버전을 정의한 Haskell Report가 발표되었어요.

시작하기 위해 필요한 것

필요한 건 텍스트 편집기와 하스켈 컴파일러예요. 아마 좋아하는 편집기는 이미 설치되어 있을 테니 그건 생략할게요. 이 튜토리얼에서는 가장 널리 쓰이는 하스켈 컴파일러인 GHC를 사용할 거예요. 가장 좋은 시작 방법은 권장되는 하스켈 설치 관리 도구인 GHCup을 다운로드하는 거예요.

GHC는 하스켈 파일(보통 .hs 확장자)을 받아 컴파일할 수 있을 뿐 아니라, 대화형 모드도 있어요. 파일과 상호작용하며 즉석에서 실험할 수 있죠. 대화형으로요. 로드한 파일의 함수를 호출하면 결과가 곧바로 표시돼요. 학습 용도로는, 매번 컴파일하고 변경한 뒤 프롬프트에서 프로그램을 실행하는 것보다 훨씬 쉽고 빠르답니다. 대화형 모드는 프롬프트에서 ghci라고 입력하면 시작돼요. 예컨대 myfunctions.hs라는 파일에 몇 가지 함수를 정의해 두었다면, :l myfunctions라고 쳐서 그 함수들을 로드한 뒤 곧바로 가지고 놀 수 있어요. 단, myfunctions.hs가 ghci를 실행한 폴더와 같은 곳에 있어야 해요. .hs 파일을 변경했다면 :l myfunctions를 다시 실행하거나, 현재 파일을 다시 로드하는 :r을 써도 같아요. 저는 보통 .hs 파일에 함수를 몇 개 정의하고, 로드해서 갖고 놀다가, 파일을 수정하고, 다시 로드하는 식으로 반복하며 실험해요. 여기서도 바로 그렇게 해 볼 거예요.