この記事では、Haskell Stack についての初歩的な説明をします。
(2022-11-20補足)現在は、GHC や Stack のインストールには GHCup を使うのが主流になっています。
はじめに
いま Haskell の開発環境を導入するといえば Stack だろうと思います。
これから Haskell の勉強を始めようと思うなら、まずは Stack の使い方を覚えることになります。
Stack は便利なツールなのですが、個人的な印象としては、最初のとっつきが悪いと思っています。
僕が初めて Stack に接したときは、「これはいったい何をするツールなのだろう」とモヤモヤしました。
ひとつのツールでいろいろな役割をこなすので、かえって何のツールか分からないのです。
また、コマンドを実行しても、実際に何が起こっているのかがよく分からないのもモヤモヤする点でした。
そういう初歩的な説明はあまり誰もしてくれません。
そこで、試しに説明をしてみようと思いました。
なお、Stack 自体のインストール方法については本記事では割愛します。
公式ドキュメントの Install/upgrade に書いてありますし、それ以外にもあちこちで解説が見つかります。
Stack でできること
主に、以下の3つをこなすツールです。
- (1) Haskell コンパイラをパソコンにインストールする。
- (2) Haskell 製のツールを、ビルドしてパソコンにインストールする。
- (3) Haskell で開発する際のプロジェクトを新規作成したり、プロジェクトをビルドしたりする。
Stack について把握していくと、(3) がメイン機能で (1) や (2) はその派生的な機能だと気づきます。
しかし、まずは (1) や (2) から把握していくのが良いと考えます。
(1) Haskell コンパイラをパソコンにインストールする
これを行うのが stack setup
コマンドです。
stack setup
実際に stack setup
コマンドを実行すると、おもむろにコンパイラである GHC のダウンロードとインストールが始まります。
初めて実行すると、ここでいきなり時間がかかることに驚くかと思います。しばらく待ちましょう。
無事に成功すると、次のコマンドでコンパイラである GHC を起動できます。
stack ghc
また、stack ghc -- --version
で GHC のバージョンを表示できます。
なお、ghc
コマンドにオプションを渡すために --
を間にはさみます(--
が間にない場合は stack
コマンドへのオプションとして扱われます)。
さらに、stack ghci
で対話環境 GHCi が起動できます。
stack ghci
Haskell の入門書などを読むなら、GHCi が使えればとりあえずは足りるかと思います。
インストール先とアンインストール方法
stack setup
で長々とダウンロード&インストールしたものは ~/.stack
ディレクトリ以下に格納されています。
Haskell 開発環境がいらなくなってアンインストールする場合は、~/.stack
ディレクトリを丸ごと削除してしまうのが簡単です。
補足
もし stack setup
が途中で失敗した場合は、もう一度 stack setup
を実行しなおせば再度ダウンロード&インストールを試みます。
stack setup
が無事終了した状態でもう一度 stack setup
を行うと、すでにダウンロード&インストール済みであるため、すぐに終了します。
(2) Haskell 製のツールを、ビルドしてパソコンにインストールする
これを行うのが stack install
コマンドです。
例えば、Haskell の開発補助ツールである stylish-haskell や HLint をインストールするには、次のコマンドを実行します。
stack install stylish-haskell
stack install hlint
実際にこれらの stack install
コマンドを実行すると、依存パッケージのダウンロードとビルドが始まります。
結構たくさんのパッケージがビルドされる場合もあり、やはり驚くかと思います。しばらく待ちましょう。
無事に成功すると、~/.local/bin
ディレクトリ以下に実行ファイルがインストールされています。
この ~/.local/bin
に PATH が通してあれば、インストールしたツールをシェル上で実行できるというわけです。
インストール先とアンインストール方法
stack install
でダウンロード&ビルドしたパッケージは ~/.stack
ディレクトリ以下にあります。
そして、最終的にできた実行ファイルを ~/.local/bin
ディレクトリにコピーするのが stack install
コマンドの仕事です。
アンインストールする場合は ~/.local/bin
ディレクトリに作成された実行ファイルを直接削除します。
~/.stack
ディレクトリ以下にもビルドしたものがあるのですが、ビルドしたものを選んで削除するのは大変なので、そのまま放置するか ~/.stack
ディレクトリごと削除するかになります。
なお、~/.local/bin
は環境によって異なるパスである場合があります。実際のパスは stack path --local-bin
コマンドで取得できます。
補足
もし stack install
が途中で失敗した場合は、もう一度 stack install
を実行しなおせば再度ダウンロード&インストールを試みます。
stack install
が無事終了した状態でもう一度 stack install
を行うと、すでにダウンロード&インストール済みであるため、すぐに終了します。
上記では stylish-haskell や HLint を例として挙げましたが、開発補助ツールでなくとも、それ以外の Haskell 製ツールをインストールすることにも使えます。
例えば、Haskell 製のツールとして有名なもののひとつ、Pandoc をインストールするには、stack install pandoc
を実行します。
(とはいえ、Pandoc をインストールしたいなら、ビルド済みバイナリをインストールした方が早いでしょうが)
(3) Haskell で開発する際のプロジェクトを新規作成したり、プロジェクトをビルドしたりする
最初にも書きましたが、これが Stack のメイン機能です。
この機能については、メイン機能だけあってあちこちで解説が見つかります。そのため、ここで詳しく書くことはしません。主なコマンドを挙げておきます。
-
stack new
: プロジェクトをテンプレートから新規作成する。 -
stack init
: プロジェクトをテンプレートを使わずに新規作成する。 -
stack setup
: プロジェクトで指定されたバージョンのコンパイラや基本パッケージをインストールする。 -
stack build
: プロジェクトをビルドする。 -
stack install
: プロジェクトをビルドして local-bin にインストールする。
プロジェクトを作成すると、プロジェクトディレクトリ内に stack.yaml
という設定ファイルができます。
なお、プロジェクトを作成して作業する場合、プロジェクトディレクトリ内に .stack-work
というディレクトリができます。ダウンロードやビルドの際には、~/.stack
だけでなく .stack-work
も使われます。
グローバルプロジェクト
(3) のコマンドを見ると気づきますが、(1) や (2) で使った stack setup
や stack install
がプロジェクトのコマンドとして存在しています。
実のところ、Stack のコマンドはみんな、プロジェクト内で使用するコマンドです。しかし、(1) や (2) の操作では、特にプロジェクトを作成したりはしませんでした。プロジェクトのない場所で Stack のコマンドを実行した場合、それはグローバルプロジェクトを使って実行したものとみなされます。
グローバルプロジェクトは ~/.stack/global-project
ディレクトリにあります。この中に、通常のプロジェクトと同様に stack.yaml
ファイルや .stack-work
ディレクトリがあります。
最初に、(3) がメイン機能で (1) や (2) はその派生的な機能だと書きました。これは、(1) や (2) はグローバルプロジェクトを使っているという以外は (3) の機能とほぼ同じであるという意味でした。
パッケージ
ここまでで、Stack の機能がなんとなく分かってきたのではないかと思います。
ただ、ひとつ重要な点を抜かして書いてきました。それはパッケージについてです。
Haskell では、様々なライブラリやツールがパッケージという形で提供されています。
そして、ひとつのパッケージが別のパッケージの機能を利用することが多いです。
stack install
のときにいくつもの依存パッケージがダウンロード&ビルドされたのを覚えているかと思います。
このパッケージという仕組みは強力ではありますが、一方で依存関係がややこしくなりがちです。
ここで、パッケージに関する用語を挙げておきます。
- Cabal : パッケージの仕様
- Hackage : 多数の Cabal パッケージを集めたリポジトリ
- Stackage : 依存関係を解決したパッケージ集を管理する場所
- snapshot : Stackage で管理されているパッケージ集
Stack は、どの snapshot を使うかを stack.yaml
の resolver
の項目で指定します。
これによって、常に特定の snapshot を使うため、依存関係に悩まされずに安定してビルドできます。
おわりに
以上、Haskell Stack についての初歩的な説明をしてみました。
これから Haskell を勉強してみたい人に少しでも役立てば幸いです。