stack script も HLS に面倒見てほしい

[Haskell Advent Calendar 2021](https://qiita.com/advent-calendar/2021/haskell), 7 日目の記事です。

# はじめに - stack script はいいぞ

Haskell を触り始めてだいぶ経ちますが、ようやく完全に理解した（分かってない）ので何かにつけて Haskell を使いたくなります。

しかしそうほいほいネタが出てくる程に発想が豊かなわけではありません。まさに「[Twitterを巡回していてわかったHaskell初心者が躓きやすいポイント8つ](https://qiita.com/lotz/items/5cbaca19d90cd168ab43#8-%E4%BD%95%E3%81%8B%E4%BD%9C%E3%82%8A%E3%81%9F%E3%81%84%E3%81%91%E3%81%A9%E3%83%8D%E3%82%BF%E3%81%8C%E3%81%AA%E3%81%84)」のうちの一つにはまってしまいそうになっていました。

そんな時、ちょっとしたスクリプトを Haskell で書いてみることに私は活路を見出しました。普段つい Bash や Python で書いちゃっているようなものを Haskell で書いちゃうわけです。そして Haskell ではそれが出来ます。`stack script` という便利なコマンドがあるのです。

ただ本記事ではその詳細については触れません。`stack script` コマンドの使い方については、例えば以下をご覧ください。

* [script interpreter + stack script でスクリプティング！](https://haskell.e-bigmoon.com/stack/tips/script-interpreter.html)
* [User guide - The Haskell Tool Stack](https://docs.haskellstack.org/en/stable/GUIDE/#script-interpreter)

stack script は専用のディレクトリを用意することなくそのファイルだけで完結できるので、大変重宝します。しかし本当にファイル一つだけでスクリプトを書いていると HLS がうまく起動してくれないという不都合がありました。というわけで、ここからが本記事の本題。

# 環境

* OS: Windows 11
* stack: winget 経由でインストール
* エディタ: VS Code
* プラグイン:
  * Haskell for Visual Studio Code
  * Haskell Syntax Highlighting

最近 Windows を 11 にアップグレードしました。ついでに winget を導入しました。ただ winget では GHC を直接インストール出来ないのでそのせいではまったというのもありそうです。

# 出てくるエラーと解消方法

仮に、スクリプトのファイルしかないディレクトリを VS Code で開いたとします。すると右下にすぐにエラーが表示されます。

## Project requires GHC but isn't installed

最初に出てくるエラーはこれです。エラーメッセージの通り、HLS が GHC を認識できていないです。これの解消法は二つあります。

**1. パスを通す**

Windows であれば、コントロールパネルから環境変数に stack によってインストールされた GHC にパスを通すことで解消することが出来ます。Linux などであれば .bashrc かなにかでパスを追加すればいいかもしれません。`stack path` コマンドを実行して表示される、`compiler-bin` のパスがこれに該当します。

この方法を使えば、それだけで HLS はちゃんと起動します。別のエラーが出てくることもないですし、そのために後述するような余計なファイルを作る必要もありません。

しかし環境変数に設定すべきパスは GHC のバージョンによって異なっており、GHC のバージョンを変更したり何らかの事情で少し古い resolver でスクリプトを書きたくなったらいちいち環境変数を変更しなければならないでしょう。これでは面倒です。

というわけで、他の方法を考えます。

**2. stack.yaml を作る**

ここで普通に `stack new` して作った場合を思い出してみます。この場合 HLS はプロジェクトで使っている GHC のパスをバージョン含め自動で認識し、ソースコードを解析してくれます。したがって `stack new` で作成される何らかのファイルの存在が重要であると推測されます。

GHC のバージョンまで特定可能な情報といえば stack の resolver です。そして resolver が記載されたファイルといえば、stack.yaml ですね。実際、以下の内容の stack.yaml を作ればこのエラー**は**出なくなります。

```yaml:stack.yaml
resolver: lts-18.18
packages: []
```

resolver のバージョンはスクリプトで使うものとそろえたほうがいいでしょう。また packages は空配列を指定しないとまたさらに別のエラーが出てきます。

## Couldn't figure out what GHC version the project is using: ...

stack.yaml を作ったことで GHC が見つからないというエラーは解消することが出来ましたが、それだけでは HLS は起動してくれませんでした。今度は GHC のバージョンはどれを使えばいいのかわからないと言ってきます。

stack.yaml に resolver のバージョンも書いているので分かりそうなものですが、エラーメッセージの続きを読むと以下のように書かれています。

> No 'hie.yaml' found. Try to discover the project type! Failed get project GHC version, since we have a none cradle

なので hie.yaml を作りましょう。stack を使っていますから、以下の内容で[^1]。

[^1]: 「[おすすめHaskellプロジェクト作成方法(ほぼ)2021年版](https://zenn.dev/autotaker/articles/haskell-setup-2021#cradle%E3%81%AE%E8%A8%AD%E5%AE%9A)」や「[[haskell] stackとHaskell Language Server双方のご機嫌を取り続けた記録](https://qiita.com/merliborn/items/63467fab96c44ed03443)」を参考にしました。

```yaml:hie.yaml
cradle:
  stack:
```

そしてエディタを再起動すれば、今度こそ HLS ちゃんが起動してスクリプトにダメだししてくれるようになります。やったね！

## まとめ

stack script はちょっとしたプログラムを書きたいときに重宝しますが、スクリプト編集中そのままでは HLS がうまく起動してくれず不便でした。解消法を考えた結果、以下のファイルを用意すればスクリプト編集中も HLS にお世話してもらえるようになりました。

* stack.yaml
* hie.yaml

ただこれらのファイルをいちいち用意しなければならないためやはりちょっと面倒です。他にもっとよい方法がありましたら教えてもらえるとうれしいです。