VSCodeでHaskellを書く環境を構築する(IntelliJ IDEAの操作感ちょい足し)

はじめに

先日、自宅のMacBook PromacOSクリーンインストールしつつCatalinaにアップデートしました。

まっさらな環境に一から環境構築していくのは楽しい作業ではあるのですが、Haskellの環境に関しては数ヶ月前に試行錯誤の末に構築したこともあり全然整理できていなくて、この機会に手順を書いておこうかなと思います。

環境

前提

macOSに以下のソフトウェアがインストール済みであること。

作成する環境について

これから作成する環境は、VSCodeIDEのような操作感を手に入れたうえで、IntelliJ IDEAの操作感をちょい足ししたような環境を目指します。

そのためには以下のツールを使用します。

Haskell IDE Engine

Haskell IDE Engine は、Language Server Protocol を介して、普通のテキストエディタIDEのようなコード補完やコンパイルエラーの表示などの機能を追加できるツールです。操作イメージは、公式の この辺 を見ると分かりやすいと思います。

github.com

なお、Haskell IDE Engineは、今のところバイナリ形式での配布はされていないため、GitHubからソースコードを落として手元の環境でビルドする必要があります。ビルド時間はそれなりに掛かります。

IntelliJ IDEA Key Bindings

IntelliJ IDEA Key Bindings は、VSCodeのキーバインディングIntelliJ IDEAのそれに置き換えるVSCodeのextensionsです。

これを使用すると、例えばVSCode上のターミナルの開閉は Option+F12 で、プロジェクトウィンドウの開閉は Command+1 でという風に、IntelliJ IDEAのショートカットキーがVSCodeでも使えるようになります。詳しい使い方は、 こちら に記載されています。

そもそもなぜこの環境にしたのか

私は普段の開発にIntelliJ IDEAやAndroid Studioなど、JetBrains製品を愛用しています。そのためHaskellIntelliJ IDEAで書きたかったのですが、専用のpluginである IntelliJ Haskell がどうも自分には合わなくて、それとHaskell IDE Engineとの出会いもあったため普段補助的に使用しているVSCodeHaskellを書くことにしました。

ただ、個人的にVSCodeの素のキーバインディングはいまいち馴染めなくて、JetBrains製品との行き来にどうしても脳内コンテキストスイッチが発生してしまいます。これを防ぐために、IntelliJ IDEA Key Bindingsを使用することにしました。

前置きが長くなりましたが、次項からは手順を書いていきたいと思います。

構築手順

1. Stackをインストール

まずは、Homebrewを使用して Stack をインストールします。 Stackは、Haskellのビルド&パッケージ管理ツールで、プロジェクト毎のGHCや依存パッケージのバージョン管理などができます。

$ brew install haskell-stack

$ stack —version
Version 2.1.3 x86_64

2. PATH の追加

Stackでインストールする各種実行ファイルは、 ~/.local/bin に保存されます。 そのため、 ~/.local/binPATH に追加しておきます。

$ echo 'export PATH=~/.local/bin:$PATH' >> ~/.bashrc
  • fishの場合
$ echo 'set -x PATH ~/.local/bin $PATH' >> ~/.config/fish/config.fish

3. stackコマンドの自動補完を設定

ログインシェルを bashzshにしている場合は、 Shell Auto-completion を設定しておくことで、Stackのサブコマンドを自動補完してくれるようになります。以下はbashの例。

$ echo 'eval "$(stack --bash-completion-script stack)"' >> ~/.bashrc

Shell Auto-completionは、残念ながら fish では未対応のようですね。

4. stack update

以下のコマンドを叩き、 ~/.stack 内のグローバルプロジェクトのフォルダを生成しておきます。

$ stack update

$ tree ~/.stack -L 2
/Users/xxx/.stack
├── config.yaml
├── global-project
│   ├── README.txt
│   ├── stack.yaml
│   └── stack.yaml.lock
├── pantry
│   ├── hackage
│   ├── pantry.sqlite3
│   └── pantry.sqlite3.pantry-write-lock
├── programs
│   └── x86_64-osx
├── setup-exe-cache
│   └── x86_64-osx
├── setup-exe-src
│   ├── setup-mPHDZzAJ.hi
│   ├── setup-mPHDZzAJ.hs
│   ├── setup-mPHDZzAJ.o
│   ├── setup-shim-mPHDZzAJ.hi
│   ├── setup-shim-mPHDZzAJ.hs
│   └── setup-shim-mPHDZzAJ.o
├── snapshots
│   └── x86_64-osx
├── stack.sqlite3
└── stack.sqlite3.pantry-write-lock

5. Haskell IDE Engineをインストール

Haskell IDE Engineをインストールする前に GMP(多倍長演算ライブラリ) を再インストールしておきます。これをやっておかないと、Haskell IDE Engineのビルドの途中でエラーになってしまいます。

$ brew reinstall gmp

Haskell IDE Engineは前述の通りバイナリ形式では配布されていないので、 GitHub からソースコードを落として手元の環境でビルドする必要があります。

まずはgit cloneして、haskell-ide-engineへchange directoryします。

$ git clone https://github.com/haskell/haskell-ide-engine --recurse-submodules
$ cd haskell-ide-engine

取りあえずhelpを確認してみましょう。

$ stack ./install.hs help

run from: stack

Usage:
    stack install.hs <target>
    or
    cabal new-run install.hs --project-file install/shake.project <target>

Targets:
    help                    Show help message including all targets

    build                   Builds hie with all installed GHCs
    build-all               Builds hie for all installed GHC versions and the data files
    build-data              Get the required data-files for `hie` (Hoogle DB)
    hie-8.2.2               Builds hie for GHC version 8.2.2
    hie-8.4.2               Builds hie for GHC version 8.4.2
    hie-8.4.3               Builds hie for GHC version 8.4.3
    hie-8.4.4               Builds hie for GHC version 8.4.4
    hie-8.6.1               Builds hie for GHC version 8.6.1
    hie-8.6.2               Builds hie for GHC version 8.6.2
    hie-8.6.3               Builds hie for GHC version 8.6.3
    hie-8.6.4               Builds hie for GHC version 8.6.4
    hie-8.6.5               Builds hie for GHC version 8.6.5
・・・省略・・・

helpの内容を見ると、GHCのそれぞれのバージョンに対応したHaskell IDE Engineが用意されていることが確認できます。今回は執筆時点の最新である 8.6.5 を指定します。

$ stack ./install.hs hie-8.6.5
$ stack ./install.hs build-data

ちなみに、ここで build-all を指定してしまうと、すべてのGHCのバージョンに対してHaskell IDE Engineをインストールしてしまうので、恐ろしく時間が掛かってしまいます。使用するGHCのバージョンが決まっているのであれば、バージョン指定するのが無難です。

しばらく待っていると、こういう表示が出れば完了です。私の環境で約42分掛かりました。

Copied executables to /Users/xxx/.local/bin:
- hie
- hie-wrapper
# stack (for stack-hie-8.6.5)
Build completed in 42m15s

$ hie --version
Version 0.12.0.0, Git revision 3ec201f76d17148f67efb02672382109342ce391 (3037 commits) x86_64 ghc-8.6.5

6. VSCodeにextensionsを追加

VSCodeのextensionsに以下を追加します。

7. hoogleのセットアップ

最後にhoogleとの同期をできるように以下のコマンドを叩きます。

$ stack install hoogle --resolver lts
$ hoogle generate

8. 完了

手順は以上です。ここまでの手順を終えると、VSCodeこういう操作 ができるようになっているはずです!

おわりに

Haskellを本格的に学ぶようになって半年くらい経ちますが、HaskellIDEやツールがまだまだ成熟していないのかなと感じています。そのため今はこの環境が自分にとって良い選択でも、状況はどんどん変わっていくと思うので、より良い環境は継続的に探していきたいと思います。

参考文献