Notice
Recent Posts
Recent Comments
Link
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Tags more
Archives
Today
Total
관리 메뉴

HASKELL

Haskell: Windows 10 에서 Haskell 설치, 내용 업데이트 본문

Environment

Haskell: Windows 10 에서 Haskell 설치, 내용 업데이트

__main__ 2021. 1. 3. 09:55

1. Windows 10 에 Haskell 을 설치하는 방법 두 가지

 

Windows 10 에서 Haskell 을 설치하는 방법은 두 가지다.

 

a. Haskell Platform 을 설치하는 방법

b. Haskell Stack 으로 Haskell 을 설치하는 방법

 

첫 번째 방법은 편하지만, 인터넷을 검색해보면 Haskell stack 으로 Haskell 을 설치하라는 글들이 보인다. Haskell 프로젝트를 직접 생성하고 필요한 package 들을 직접 설정하는 과정을 겪어야지 Haskell 프로그래밍에 대해서 더 잘 알 수 있다는 것이 요지인 것 같다. 여기서 더 잘 알 수 있다는 표현을 풀어 설명하자면, 그 의미는 다음과 같다.

 

Haskell 언어도 다른 언어들처럼 버전이란 것이 있다. 예를 들면, python 2.7 인지 python 3.6 인지, Java 8 인지 Java 11 인지 하는 프로그래밍 언어 자체의 버전이다. 문제는 한 버전에서 작성된 코드가 다른 버전에서 작동하지 않거나 문제가 발생할 수 있다는 것이다. 그리고 하나의 버전에 호환되는 package 들의 dependency 라는 매우 성가시고 좌절스러운 문제도 발생할 수 있다. Haskell platform 이란 것도 Haskell 언어의 특정 버전과 그와 호환되는 여러 가지의 package 들을 합쳐 놓은 것으로 본다면, 그러한 프로그래밍 언어 자체와 각종 package 들의 호환성 문제에서 자유로울 수가 없다.

 

그러나 Haskell stack 이란 것을 사용하면 dependency problem 에서 자유로울 수 있건, 최소한 뭐가 문제인지 찾아서 해결할 수 있다. Local project 를 생성하고, stack.yaml 파일에 Haskell programming 언어의 특정 버전이 무엇인지, package dependency 등에 대해 명시를 해 놓는다면, stack setup 이나 stack build 등의 명령을 실행하면 자동으로 해당 버전의 Haskell 언어와 그 버전에 해당되는 package 들을 자동으로 알아서 설치하고 연결한다. 이러한 package manager 에 해당되는 기능은 여러 언어에서 볼 수 있는, 매우 편리한 기능이다.

 

2. Haskell stack 으로 Windows 10 에 Haskell 을 설치하는 팁

 

그런데 여기서 Haskell stack 으로 Windows 10 에 Haskell 을 설치하는데 중요한 것들이 있다.

 

a. Haskell programming language 자체가 시간이 지나면서 버전이 달라지는데, 그 때마다 새로운 버전을 설치하는 것은 hard drive 혹은 ssd 공간을 낭비하는 것이다. 공간 자체를 낭비한다는 것도 비효율적이기도 하지만, 새로운 버전을 깔 때마다 꽤 오랜 시간이 소요된다는 것, 이전 버전에 호환되는 패키지들과 새로운 버전의 Haskell 이 호환되지 못 할 수 있다는 등의 귀찮고 성가신 문제가 계속 발생한다. 안 그래도 언어 자체가 어렵고 생소한데, 설치부터 dependency 문제로 어떻게 해결할 것인지 난감하게 되면 그냥 포기하란 거다. 그러니 아예 처음부터 어떤 버전의 Haskell 을 사용할 것인지, 해당 snapshot 에 속해 있는 package 버전이 무엇인지 찾아서 명시하고 시작하는 것이 시간과 에너지 낭비를 줄이는 팁이다.

 

b. Haskell 이란 언어는 C, python, go 등의 언어와 다르게 그 용량이 어마어마하다. 설치를 다 하고 보면, 3기가를 훌쩍 넘어 4기가에 가깝고, 자칫 여러 버전의 Haskell 이라도 설치되는 경우에는 6기가를 훌쩍 넘어선다. 반복하지만, 그래서 특정 버전의 Haskell 과 그 버전(snapshot)에 해당하는 package 들만 설치해야 한다는 것이다.

 

c. Haskell stack 을 아무 생각도 없이 Windows 10 운영 체제의 PC 에 설치하면, 산만하게도 sr 등의 여러 곳에 Haskell 이 설치되게 된다. PC 파일이나 폴더 관리에 강박증을 가지고 있는 사람이라면, 그렇게 지저분하게 뭔가 PC 에 설치되는 것을 보는 것은 고통 그 자체다. 그러니 한 곳에 Haskell 과 관련된 모든 것을 설치하거나, 가능하다면 portable 하도록 설치할 수 있으면 굉장히 편리하다. 의외로 그 방법은 간단하다.

 

3. 설치 경로 지정, 혹은 Portable Haskell 만들기

 

1) stack.exe 파일을 분리

 

먼저 Haskell stack 을 운영 체제가 설치된 드라이브가 아닌, D 드라이브나 용량이 큰 USB 에 설치한다. Haskell stack 설치는 그냥 압축이 풀리는 것과 같이 간단하므로, 일단 Windows 64 bits installer 로 설치한 후에 설치된 폴더의 stack.exe 파일만 원하는 폴더에 옮겨도 된다.

 

2) STACK_ROOT 환경 변수 등록

 

실행 파일을 옮긴다고 아무 폴더에서 cmd 띄워 명령 찍어봤자 실행되지 않고 그런 파일 없다고 에러 뜬다. 그러니 stack.exe 파일을 옮긴 경로를 환경 변수에 등록해주어야 한다. 그래야 아무 폴더에서 cmd 창을 띄워 stack 관련 명령을 치더라도 실행이 된다. 그리고 또 하나 환경 변수에 등록해주어야 할 중요한 것이 있다. 경로 지정과는 미묘하게 차이가 있는 것으로, STACK_ROOT 이란 거다. STACK_ROOT 는 말 그대로 stack.exe 가 위치한 폴더로, stack.exe 가 root 폴더로 인식하게 된다.

 

3) config.yaml 파일로 Haskell 이 설치될 경로 지정

 

다음으로 Haskell 이 설치될 경로를 지정해주는 거다. stack.exe 명령으로 Haskell 을 설치할 때, Haskell stack 은 Haskell 을 어디에 설치하는 걸까? 미리 정해진 default 경로란 것이 있을 거다. 그냥 아무 생각을 하지 않고 시키는데로 나두면, C:/sr 등의 이상한 경로를 새로 만들어지고 그 아래에 잔뜩 뭐가 생겨버린다. 그러니 깨꿋하게 한 곳에만 설치하거나 portable 로 만들기 위해서는, Haskell stack 이 어디에 Haskell 을 설치할 것인지 알려주면 된다. 인터넷을 검색해보니 그런 방법이 있었다. Haskell stack 이 설치된 폴더에, 즉 stack.exe 파일이 있는 폴더에 config.yaml 파일을 만들고 아래와 같은 내용을 넣으면 된다. 매우 간단하다.

 

# In "config.yaml"
local-programs-path: D:\HaskellStack\programs

 

4) golbal vs. local project

 

설치될 Haskell 버전은 하나로 족하다. 이건 stack.yaml 파일에 resolver: lts-15.27 등으로 특정 버전의 Haskell 버전으로 정하면 하나로 통일할 수 있다. 쓸데없이 여러 버전이 설치되는 것은 미리 신경을 써서 막을 수 있다는 이야기다. 그런데 서로 다른 버전의 Haskell snapshot 이 설치되는 것 이외에도 불필요한 중복의 문제가 있다. 바로 global project 와 local project 문제다. stack new 라는 명령으로 새로운 Haskell project 를 생성하여 그 폴더에 들어가서 satck setup 등의 명령을 실행하는 것과, project 가 아닌 아무 폴더에서 stack ghci 등의 명령을 실행하는 것은 천지차이다. 전자는 local project 요, 후자는 global project 이기 때문이다. 엄연히 다르며, 이전에 만든 STACK_ROOT 경로에 가서 살펴보면, global project 에 대한 Haskell 과, local project 에대한 Haskell 이 따로 중복되어 설치되어 있는 것을 알게 된다. 이 역시 낭비요 비효율이다. 오히려 똑같은 버전이 다른 곳에 중복되어 설치될 수 있다는 점에서, 더 심한 낭비요 비효율이다. 물론 project 를 만들지 않은 상태에서 ghci repl 을 띄우고 사용해보고 싶으면 모르겠지만, 이미 local project 를 만들고 그 안에서 ghci repl 이고 뭐고 잔뜩 맘대로 할 수 있는데 따로 global project 를 위해 따로 Haskell 을 설치할 이유가 없다. 그러니 함부로 project 가 아닌 폴더에서 cmd 를 띄워서 stack 명령을 사용하지 말자. 그렇게 하면 Haskell stack 은 "아, 아무 폴더에서 ghci repl 을 사용하고 싶은가 보다." 라고 생각하고, global project 에 대한 Haskell 을 따로 설치해버린다.

 

4. 필요한 Package 설치

 

지금까지 과정을 요약하면 이렇다. 신경써야 할 것이 이런 것들이란 소리다. stack.exe 를 원하는 폴더에 옮기고, 그 폴더를 환경변수에 STACK_ROOT 로 등록하고, path 항목에 경로 지정도 해주어 아무 폴더에서나 stack 이 실행될 수 있도록 해주고, 그 폴더에 config.yaml 파일을 만들고 Haskell 이 설치될 경로를 지정해준다. 그리고 stack new 로 새로운 local project 를 만들어 그 local project 의 stack.yaml 파일에 명시한 버전의 Haskell 만 설치될 수 있도록 해준다. 따로 project 가 아닌 아무 폴더에서 stack ghci 명령을 실행하지 않도록 한다. 그러면 global project 로 인식해서 따로 global project 에 대한 Haskell 을 중복해서 설치해버리기 때문이다. 그런데 이 과정은 가장 기본적인 Haskell 을 설치한 것 뿐이다. 그런데 기본적인 것만으로 Haskell 프로그래밍을 하지는 않는다. 예를 들면, random 과 관련된 함수를 사용하려면 random package (혹은 module) 를 import 해야 한다. 그런데 *.hs 파일 서두에 import random 한다고 다 되는 것은 아니다. 내 pc 에는 그런 package 혹은 module 이 없기 때문이다. random 관련한 함수들을 사용하기 위해서는 stack.yaml 혹은 package.yaml 파일 안에 무슨 package 들을 따로 설치해서 사용할 것인지 미리 명시해주어야만 한다. 예를 들면, 아래와 같은 식이다. 아래는 필요한 package 를 설치하는 방법 중 하나의 예이다. 정확하게 설정된 것인지는 초보라 잘 모르지만, 아무튼 잘 작동하지 그리 틀린 것 같지는 않다.

 

1) stack.yaml 에 package 추가

 

나쁜 방법, 이 방법은 설치된 Haskell snapshot 버전이 포함하지 않는 package 를 설치할 때나 쓰는 방법이다. 설치하려고 하는 package 가 이미 설치된 Haskell snapshot 에 포함되어 있다면, 그건 엄밀하게 "extra" dependency 를 갖는 package 가 아니다. 그냥 package.yaml 에 package 이름만 dependencies 항목에 추가하면 되는, 이미 Haskell snapshot 에 포함되어 있고, Haskell snapshot 에 이미 포함되어 있는 package 라는 것을 알고 있다. 그러니 고오급 Haskeller 가 되어 사용하고 있는 Haskell snapshot 버전이 포함하지 않는 다른 "extra" package 를 사용할 수준에 이르기 전에는, 그냥 stack.yaml 파일은 되도록 건드리지 말자. 단지 resolver: lts-16.27 항목만, snapshot 을 통일시키켜 불필요하게 여러 버전의 Haskell 들이 설치되지 않도록 하는 목적으로만 사용하면 된다.

 

extra-deps:
- HsYAML-0.2.1.0
- HsYAML-aeson-0.2.0.0
- ghc-lib-parser-8.10.3.20201220
- stylish-haskell-0.11.0.3
- hlint-3.1.6
- split-0.2.3.4
- random-1.1

 

위의 stack.yaml 파일을 보자. 복잡한 숫자들이 엉망으로 package 항목 뒤에 잔뜩 붙어 있다. package 들에 대한 버전이다. 즉, stack.yaml 파일에 package 이름과 해당 Haskell snapshot 버전에 대한 package 버전을 명시한 것이다. 이걸 다른 말로 표현하자면, 내가 필요한 package 가 있어 stack.yaml 파일을 수정하는 식으로 그 package 를 추가하고 싶다면, 설치된 package 버전을 알아야지만 extra-depths 항목에 추가할 수 있다는 것이다. 그런데 인터넷에서 resolver: lts-16.27 을 검색하면, 그 버전의 Haskell snapshot 에 포함된 package 들과 해당 버전 목록이 뜬다. 그 말은, 이미 설치된 Haskell snapshot 은 자기가 포함하는 여러 가지의 package 들의 버전 정보를 이미 알고 있다는 소리다. 그러니 추가하고 싶은 package 를 찾아 버전 숫자를 같이 stack.yaml 파일의 extra-depths 항목에 추가하는 것은, 일종의 에너지 낭비다.  

 

2) package.yaml

 

필요한 package 가 있으면 일단 해당 Haskell snapshot 을 검색하여 원하는 package 가 있으면, 그냥 그 이름만 package.yaml 파일의 dependencies 항목에 적고, stack build 명령만 치면 끝이다. 설치된 Haskell snapshot 버전에 포함되어 있다고 검색되는 package 라면, 그냥 이 방법이 제일 좋다. 

 

dependencies:
- base >= 4.7 && < 5
library:
source-dirs: src
executables:
h99-exe:
main: Main.hs
source-dirs: app
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- h99
- hlint
- stylish-haskell
- split
- random
tests:
h99-test:
main: Spec.hs
source-dirs: test
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- h99

 

Haskell 의 package 나 project 구조를 잘 몰랐을 때 매우 헤매었으니 여기서 다시 반복하여 정리할 필요가 있겠다. Haskell package 를 설치하는 방법은 대략 세 가지다. stack,yaml 파일, package.yaml 파일, cabal 파일 수정 등이다. 그 중에 앞의 두 가지가 중요하고, 그 둘의 차이를 알아야 할 필요가 있다. (a) stack.yaml 에 버전을 명시한 package 들을 extra-deps: 항목에 추가하는 것과, (b) package.yaml 에 명시적 버전 숫자 없이 package 이름들만 dependencies: 항목에 추가하는 것과 뭐가 다른 것인지? 어떤 방법이 편하고 쉬운 거인지? package.yaml 파일에 package 이름들만 dependencies: 항목에 추가하는 방법이 더 낫다고 생각한다. (그게 맞는지는 모르겠지만) 그렇게 하면 stack.yaml 에 resolver: lts-16.27 등으로 정의된 특정 Haskell snapshot 에 포함된 각각의 특정 버전의 package 들이 자동으로 알아서 설치되기 때문이다. 반면에 일일히 stack.yaml 파일의 extra-dependencies: 항목에다가 package 들 중에 필요한 것들을 버전 숫자를 일일히 적어주어야만 한다. 편하지 않다.

 

그리고 stack.yaml 파일의 extra-dependencies: 항목은 그런 용도가 아니다. extra-dependencies 라는 말 그대로, 특정 Haskell snapshot 에 포함되지 않은, 말 그대로 (extra) 그 이외의 package 등을 일부러 억지로 가져다 쓸 경우에만 extra-dependencies: 항목에 추가하는 용도다. 이미 특정 버전의 Haskell snapshot 에 포함되어 있다고 명시된 버전의 package 들을 stack.yaml 파일의 extra-dependencies: 항목에 숫자까지 쓰면서 추가하는 것은 쓸데없는 일이다. 반복하여 강조하지만, 특정 버전의 Haskell snapshot 은 어떤 버전의 package 들을 가지고 있고, 각각의 버전이 무엇인지 이미 알고 있기 때문이다. 그저 package.yaml 파일에 버전 정보를 명시적으로 기입하지 않고 그냥 package 이름만 쓰는 식으로 앞의 방법만으로 충분하다.

 

5. 설치하면서 만나는 문제들

 

1) chcp 65001

 

설치하면서 cmd 창을 띄우고 우선 chcp 65001 이라고 친다. cmd 창에서 encoding 관련하여 쓸데없는 문제가 생길 것을 미연에 방지하기 위해서다. 그리고 관리자 권한으로 cmd 창을 띄워 설치하고, 에러 메지시에서 Permission 관련한 내용이 뜨면 백신 프로그램이 원인일 수 있으니 반복하여 명령을 쳐보면서 백신이 파일 접근을 허용하겠느냐는 메시지가 뜨도록 기다려 보거나 백신을 잠시 꺼두고 설치를 진행해보는 것도 고려.

 

2) 에러-설치-에러 반복

 

그리고 이상하게도 에러가 자주 발생하는데, 그런 경우 포기하지 말고 똑같은 명령을 반복해서 쳐보면 조금씩 설치-에러 과정을 반복하면서 하나 둘 씩 설치되다가 결국엔 모두 제대로 설치되기도 한다. 어떻게 된 영문인지 모르는데, 뭔가 반복하면 하나씩이라도 설치가 되니 계속 반복할 수밖에. Msys2 등이 설치되는 것으로 볼 때, Haskell 이란 프로그래밍 언어로 뭔가 하기에는 linux 환경이 최적이고, Windows 10 에서 뭔가 환경 설정을 만들기 위해 설치가 진행되는 과정에서 자잘한 문제들이 생기는 것 같다. 그렇다고 Linux 로 운영 체제를 완전히 바꿀 수도 없다. Linux 를 dual booting 등으로 억지로 설치는 해볼 수 있겠지만, 써 본 적이 없어서 일단 너무나 낯설어 진입 장벽이 너무 높기 때문이다. 파일 시스템도 어떻게 돌아가는지 모르겠고, 심지어 폴더에서 파일을 옮기는 것조차 어렵다.

 

3) snapshot, resolver 문제

 

반복해서 명령을 쳐봐도 계속 에러가 날 때가 있다. 설치되어야 할 package 들의 갯수가 줄어들지 않고 그대로 계속 있으면서 에러 메시지가 똑같이 반복되는 경우다. 그 때는 명령 반복한다고 해결될 수 있는 상황이 아니다. 그럴 때는 뭔가 package 간에 dependency 문제로 초보자가 쉽게 해결하기 힘들다. 에러 메시지를 읽어보면 약간의 힌트를 얻을 수 있지만, 그렇다고 해서 문제가 쉽게 해결되지 않는다. 그러니 snapshot 을 정하는데 신중할 필요가 있다. 너무 최신의 것을 설치할 필요도 없고, 너무 오래된 것도 문제가 생길 수 있다. 적당히 최신 버전보다 한 두 버전 낮은 것으로 정해서 설치해보는 방법을 써 볼 수도 있겠다. stylish-haskell 과 hlint 라는 package 들은 계속 사용하는 것들이니, 그 package 들의 버전을 정의하고 있는 snapshot 버전을 선택하는 팁도 있다.

 

일단 dependency 문제란 것이 연달아 나타나기 시작하면 초보자로서 정말 난감하다. 자칫하다가는 해결해보려다 새벽까지 붙잡고 있게 될 수도 있다. 취미로 치매 안 걸리려고 두뇌 회전용으로 독학하는데 그럴 필요는 없지만 오기가 생겨 그럴 수도 있다는 소리다. 구글링이 도움이 될 때도 있지만, 워낙 Haskell 언어에 대한 인기가 없어서 원하는 답변을 찾기 힘들 수 있다. 그럴 때는 작성하던 소스코드를 다른 곳에 백업하고 다시 project 를 만들어 처음부터 다시 잘 작동하는 빈 project 를 만들고, 그곳에다가 백업해놓았던 소스코드를 다시 옮기는 방법을 써서 해결해볼 수도 있다.

 

때로는 설치 과정의 문제를 해결하지 못 할 수도 있다. 그래서 앞에 언급한 portable 로 만들거나 운영 체제가 설치되지 않은 다른 드라이브 등에 Haskell 을 설치하는 것이 매우 유용하다. 왜냐하면, 일단 설치에 성공하여 제대로 작동하는 버전이 C: 드라이브가 아닌 곳에 잘 저장되어 보관될 수 있기 때문이다. 여차해서 C: 드라이브를 시스템 이미지 복원을 하더라도 성공한 설치 버전은 그대로 다른 드라이브나 USB 등에 남아 있는 것이니 쉽게 경로만 다시 설정해주면 다시 설치하지 않고서도 쉽게 다시 Haskell 을 실행하여 프로그래밍을 할 수 있다는 것은 큰 장점이다.

'Environment' 카테고리의 다른 글

Haskell: Warning: Multiple files use the same module name:  (0) 2021.01.03
Emacs + Haskell-Mode  (0) 2020.11.23
Docker for haskell  (0) 2019.03.19
Haskell project setting - cabal file  (0) 2019.01.27
How to Uninstall Old GHC  (0) 2019.01.11
Comments