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

Emacs + Haskell-Mode 본문

Environment

Emacs + Haskell-Mode

__main__ 2020. 11. 23. 17:56

I. Install Haskell by Stack 

1. Stack 을 다운로드, 설치 

- Home - The Haskell Tool Stack (haskellstack.org)

- WIndows 64-bit installer 다운로드, 설치(Haskell 설치를 원하는 폴더에)

- 'config.yaml' 파일 하나 만들고 다음을 추가 

local-programs-path: D:\HaskellStack\programs

- 이렇게 하면 Haskell이 C 드라이브 AppData 등의 여러 곳에 산만하게 설치되지 않고, 원하는 폴더 내에 Haskell 파일 모두 한 곳에 모을 수 있다. C 드라이브 용량이 적고, 지저분해지면 PC가 느려질 수 있으니, D: 드라이브나 USB에 portable 하게 만드는 의미다. 

 

2. Stack 으로 새로운 local-project 만들기 

- 원하는 폴더에서 `stack new hello` 명령을 도스창에서 실행하면 hello 라는 폴더가 만들어지며, 그 폴더에 들어가보면 `stack.yaml`, `package.yaml` 파일 등이 자동으로 만들어진다. 

 

3. Stack 으로 Haskell 다운로드 및 build 하기

- local-project 폴더 내의 stack.yaml 파일을 보면 `resolverlts-14.20` 라는 부분이 있는데, 특정한 version의 Haskell을 다운로드 받으라고 정해주는 의미다. 이 부분을 원하는 버전으로 바꿀 수도 있고, 그냥 놔 둔 채로 다음과 같이 Haskell을 설치할 수도 있다. 

 

- `stack setup` 명령을 실행하면 꽤 오랜 시간 Haskell을 설치한다. 설치 폴더는 위에서 설정한 `local-programs-path` 이다. 

- `stack build` 명령을 실행하면, local-project 가 빌드되어 실행 파일이 만들어진다. 

 

 

II. Emacs + haskell-mode

1. Emacs 를 설치 

- MIRROR.YONGBOK.NET - /gnu/emacs/windows/

- Windows 10 64-bit system용 다운로드, 압출 풀고 bin/runemacs.exe 파일 실행

 

2. Emacs 설정 파일 위치 지정

- D:/util/emacs/share/emacs/site-lisp/site-start.el 파일 만들고 내용 추가

(defun set-home-dir (dir)
"Set a new HOME directory. This is where Emacs will look for init files and
where '~' will default to."
(setenv "HOME" dir)
(message (format "HOME location is %s" (getenv "HOME"))))
(set-home-dir "D:/util/emacs")

 

3. MELPA 추가 

- D:/util/emacs/.emacs 파일에 다음과 같은 내용 추가

- Getting Started - MELPA

(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
;; Comment/uncomment this line to enable MELPA Stable if desired. See `package-archive-priorities`
;; and `package-pinned-packages`. Most users will not need or want to do this.
;;(add-to-list 'package-archives '("melpa-stable" . "https://stable.melpa.org/packages/") t)
(package-initialize)

 

4. Haskell-mode 설치 

- M-x package-install RET haskell-mode

 

5. 테스트

- Emacs 다시 띄우고 Haskell 파일 아무거나 만들어 코딩

- C-c C-l 해서 파일을 GHCi REPL 창으로 로딩하려고 할 때마다 다음과 같은 에러 등장

Error message: The Haskell process *** has died.

- D:/util/emacs/.emacs 파일 안에 다음과 같은 내용을 추가 (결국 파일 인코딩의 문제였다!)

(set-language-environment 'utf-8)

- 이제 C-c C-l 하면 작업 파일이 cabal repl에 로딩되어 제대로 작동

 

6. 설정 파일

- Emacs configuration file example (`init.el` or `.emacs` file)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; The default is 800 kilobytes. Measured in bytes.
(setq gc-cons-threshold (* 50 1000 1000))
;; Profile emacs startup
(add-hook 'emacs-startup-hook
(lambda ()
(message "*** Emacs loaded in %s with %d garbage collections."
(format "%.2f seconds"
(float-time
(time-subtract after-init-time before-init-time)))
gcs-done)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; package source
(require 'package)
(setq package-archives '(("melpa" . "https://melpa.org/packages/")
("melpa-stable" . "https://stable.melpa.org/packages/")
("org" . "https://orgmode.org/elpa/")
("elpa" . "https://elpa.gnu.org/packages/")))
(package-initialize)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; use-package - more convenient package manager
(when (not (package-installed-p 'use-package))
(package-refresh-contents)
(package-install 'use-package))
;; install package automatically if not already present on your system
(require 'use-package-ensure)
(setq use-package-always-ensure t)
;; keep your packages updated automatically
(use-package auto-package-update
:config
(setq auto-package-update-delete-old-versions t)
(setq auto-package-update-hide-results t)
(auto-package-update-maybe))
;; org-mode config
(use-package org
:config
(setq org-hide-emphasis-markers t)
(global-set-key "\C-ca" 'org-agenda)
(setq org-src-fontify-natively t)
(setq org-babel-load-languages
'((awk . t)
(C . t)
(calc . t)
(css . t)
(ditaa . t)
(emacs-lisp . t)
(gnuplot . t)
(haskell . t)
(js . t)
(lisp . t)
(org . t)
(plantuml . t)
(python . t)
(scheme . t)
(shell . t)
(sql . t)))
;; Activate Babel languages
(org-babel-do-load-languages
'org-babel-load-languages
org-babel-load-languages))
;; key setting
(global-set-key [f12] 'shell)
(global-set-key (kbd "<escape>") 'keyboard-escape-quit)
;; org-bullet
(use-package org-bullets
:ensure t
:config
(add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))
;; haskell-mode
(use-package haskell-mode
:ensure t
:init
(add-hook 'haskell-mode-hook 'structured-haskell-mode)
(add-hook 'haskell-mode-hook 'interactive-haskell-mode)
:mode (("\\.hs\\'" . haskell-mode)
("\\.cabal\\'" . haskell-cabal-mode)
("\\.hcr\\'" . haskell-core-mode))
:custom
(haskell-process-type 'stack-ghci))
:config
(setq tab-width 2)
;; company mode
(use-package company
:ensure t
:init
(add-hook 'after-init-hook 'global-company-mode)
:config
(setq company-idle-delay 0)
(setq company-show-numbers "on"))
;; company-ghci mode
(use-package company-ghci
:ensure t
:after (pos-tip)
:config
(defun show-hoogle-info-in-popup ()
(pos-tip-show (company-ghci/hoogle-info (symbol-at-point)) nil nil nil -1))
(defun company-ghci-setup ()
(push 'company-ghci company-backends)
(define-key evil-normal-state-map (kbd "C-;") (lambda () (interactive) (show-hoogle-info-in-popup))))
(add-hook 'haskell-interactive-mode-hook 'company-mode)
(add-hook 'haskell-mode-hook 'company-ghci-setup))
;; autocomplete
(use-package auto-complete
:ensure t
:diminish auto-complete-mode
:config
(require 'auto-complete-config)
(ac-config-default))
;; hl-line
(use-package hl-line
;; visible current line
:ensure t
:diminish global-hl-line-mode
:config (global-hl-line-mode))
;; highlight-parentheses
(use-package highlight-parentheses
:ensure t
:diminish highlight-parentheses-mode
:commands highlight-parentheses-mode)
;; highlight multiple occurences
(use-package highlight-symbol
:ensure t
:bind (("M-p" . highlight-symbol-prev)
("M-n" . highlight-symbol-next)
("M-'" . highlight-symbol-query-replace))
:init
(defun highlight-symbol-first ()
"Jump to the first location of symbol at point."
(interactive)
(push-mark)
(eval
`(progn
(goto-char (point-min))
(search-forward-regexp
(rx symbol-start ,(thing-at-point 'symbol) symbol-end)
nil t)
(beginning-of-thing 'symbol))))
(defun highlight-symbol-last ()
"Jump to the last location of symbol at point."
(interactive)
(push-mark)
(eval
`(progn
(goto-char (point-max))
(search-backward-regexp
(rx symbol-start ,(thing-at-point 'symbol) symbol-end)
nil t))))
(bind-keys ("M-P" . highlight-symbol-first)
("M-N" . highlight-symbol-last)))
;; iedit mode
(use-package iedit
:ensure t
:diminish iedit-mode
:bind ("C-'" . iedit-mode))
;; spaceline configuration
(use-package spaceline
:ensure t
:config
(setq-default mode-line-format '("%e" (:eval (spaceline-ml-main))))
)
(use-package spaceline-config
:ensure spaceline
:config
(spaceline-helm-mode 1)
(spaceline-emacs-theme)
)
;; spaceline-all-the-icons
(use-package spaceline-all-the-icons
:ensure t
:config
(spaceline-all-the-icons--setup-anzu) ;; Enable anzu searching
(spaceline-all-the-icons--setup-package-updates) ;; Enable package update indicator
(spaceline-all-the-icons--setup-git-ahead) ;; Enable # of commits ahead of upstream in git
(spaceline-all-the-icons--setup-paradox) ;; Enable Paradox mode line
(spaceline-all-the-icons--setup-neotree) ;; Enable Neotree mode line
)
;; multiple cursors
(use-package multiple-cursors
:ensure t
:defer t
:bind (("C-S-c C-S-c" . mc/edit-lines)
("C->" . mc/mark-next-like-this)
("C-<" . mc/mark-previous-like-this)
;; ("C-c C-<" . mc/mark-all-like-this)
("C-c o" . mc/mark-all-like-this)
)
)
;; which-key - it shows which combos are setup while we are typing
(use-package which-key
:ensure t
:diminish which-key-mode
:config
(which-key-mode 1)
(which-key-setup-side-window-right)
(setq which-key-idle-delay 0.1))
;; iedit-mode
(use-package iedit
:ensure t
:diminish iedit-mode
:bind ("C-`" . iedit-mode))
;; avy
(use-package avy
:ensure t
:bind
("C-." . avy-goto-word-or-subword-1)
("C-," . avy-goto-char-2)
:config
(setq avy-background t))
;; ido
(use-package ido-vertical-mode
:config
(ido-mode t)
(ido-everywhere t)
(ido-vertical-mode 1)
(setq ido-vertical-define-keys 'C-n-and-C-p-only))
;; icomplete-vertical
(use-package icomplete-vertical
:ensure t
:demand t
:custom
(completion-styles '(partial-completion substring))
(completion-category-overrides '((file (styles basic substring))))
(read-file-name-completion-ignore-case t)
(read-buffer-completion-ignore-case t)
(completion-ignore-case t)
:config
(icomplete-mode)
(icomplete-vertical-mode)
:bind (:map icomplete-minibuffer-map
("<down>" . icomplete-forward-completions)
("C-n" . icomplete-forward-completions)
("<up>" . icomplete-backward-completions)
("C-p" . icomplete-backward-completions)
("C-v" . icomplete-vertical-toggle)))
;; gruvbox theme
(use-package gruvbox-theme
:ensure t
:config
(load-theme 'gruvbox-dark-hard t))
;; turn page breaks into lines
(use-package page-break-lines
:ensure t
:init (global-page-break-lines-mode)
:diminish page-break-lines-mode)
;; add stripes to a buffer
(use-package stripe-buffer
:disabled t
:ensure t
:init (add-hook 'dired-mode-hook #'stripe-buffer-mode))
;; ibuffer
(use-package ibuffer
:bind ("C-x C-b" . ibuffer))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; my custom settings
(menu-bar-mode -1) ;; hide menu bar
(tool-bar-mode -1) ;; hide tool bar
(scroll-bar-mode -1) ;; hide scroll bar
(set-language-environment "Korean") ;; korean environment
(prefer-coding-system 'utf-8) ;; encoding UTF-8
(set-language-environment 'utf-8) ;; encoding UTF-8
(setq make-backup-files nil) ;; no backup file
(setq-default column-number-mode t) ;; column number
(show-paren-mode t) ;; parenthesis
(setq show-paren-delay 0)
(electric-indent-mode 1) ;; indent
(global-linum-mode 1) ;; line number
(display-time) ;; display time
(setq system-time-locale "C") ;; time format English
(defalias 'yes-or-no-p 'y-or-n-p)
(setq inhibit-startup-screen t) ;; skip welcome screen
(windmove-default-keybindings) ;; Let me switch windows with shift-arrows instead of "C-x o" all the time
(setq-default line-spacing 0.2) ;; line space
(global-font-lock-mode 1) ;; syntax highlighting
(ido-mode t)
(ido-everywhere t)
;; (add-hook 'emacs-startup-hook 'toggle-frame-maximized)
(when window-system (set-frame-position (selected-frame) 960 0))
(add-to-list 'default-frame-alist '(height . 43))
(add-to-list 'default-frame-alist '(width . 90))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; custom settings (automatically modified by Emacs)
(custom-set-variables
;; custom-set-variables was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(column-number-mode t)
'(org-agenda-files
'("c:/Users/k/OneDrive/study/myhs/h99/src/org_practice.org"))
'(package-selected-packages '(auto-package-update use-package))
'(show-paren-mode t))
(custom-set-faces
;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(default ((t (:family "Ubuntu Mono" :foundry "outline" :slant normal :weight normal :height 158 :width normal)))))
Comments