はじめに
カジュアルに Haskell スクリプトを書く方法をいろいろ模索していたのですが、Nix を使う方法に落ち着きました。
完成形は https://github.com/logicoffee/nix-haskript に置いてあります。
Nix とは
Nix は自分のことを以下のように言っています。
Nix, the purely functional package manager
分離可能かつ共有可能な環境を構成することができるという意味では Docker のような側面を持っています。
また、ホストマシンのグローバルな環境を構成することができるという意味ではパッケージマネージャーの側面も持っています。
準備
Nix のインストール
Nix のインストールは Zero to Nix の方法でやるのをおすすめします。
書いてあるとおりにコマンドを実行すれば完了します。
direnv のインストール
direnv は必須ではないですが、Nix と連携させるととても便利なので導入するのがおすすめです。
自分の場合、グローバルにインストールするパッケージは home-manager で管理しているのですが、home-manager の導入自体も面倒なので、以下のようなコマンドでさくっとインストールしてしまうのがいいでしょう。もちろん Homebrew などでインストール済みのものがあればそれを使うのでも構いません。
nix profile install direnv
使い方
以下を順に実行します。
git clone https://github.com/logicoffee/nix-haskript
cd nix-haskript
direnv allow
direnv がアクティベートされると、ghc などがインストールされます。それが完了すると、パス内に ghc が存在するため、以下のように Haskell スクリプトを実行することができます。
$ runghc main.hs
"foo"
これにて、ラフに Haskell スクリプトを実行する環境を手に入れることができました!
解説
ファイル構成
ファイル | 説明 |
---|---|
flake.nix | 必要なライブラリやスクリプトのコンパイル方法などを記述 |
flake.lock | nixpkgs のコミットハッシュなどを保持 |
hie.yaml | haskell-language-server の設定ファイル |
main.hs | 略 |
Dockerfile | 略 |
GHC バージョンと Haskell パッケージ
GHC バージョンは以下の部分で変更できます。必要な Haskell パッケージもここに列挙しましょう。Nix expression のリスト表記はコンマが不要である点に注意です。
また、追加可能な Haskell パッケージは ここ で検索できます。
ghc = (pkgs.haskell.packages.ghc96.ghcWithPackages (p: with p; [
haskell-language-server
text
]));
その他依存プログラム
開発時に必要なプログラムは packages
に列挙します。
devShell = pkgs.mkShell {
packages = [ ghc ];
};
例えば cowsay
コマンドが欲しければ以下のように追記します。
devShell = pkgs.mkShell {
packages = [ ghc pkgs.cowsay ];
};
コンパイル
ローカルで動かす分には runghc
を使えばいいですが、例えばプログラムを Docker 化したい場合はインストール手順を書く必要があります。
コンパイル時に追加でプログラムが必要な場合は、上の devShell
と同様に、buildInputs = [ ghc pkgs.cowsay ]
のように書きます。
packages.default = pkgs.stdenv.mkDerivation {
name = "";
buildInputs = [ ghc ];
src = ./.;
buildPhase = ''
ghc main.hs
'';
installPhase = ''
mkdir -p $out/bin
cp main $out/bin
'';
};
nixpkgs のバージョン固定
nixpkgs のバージョンを固定したい場合は以下のように変更します。
- nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
+ nixpkgs.url = "github:nixos/nixpkgs/nixos-24.05";
おわりに
いろいろ試行錯誤してやっとこさ Nix ファイルの書き方が分かってきました。でもこれで Haskell スクリプティングは手軽になりました。
一方で Haskell プロジェクトを構成するツールである stack や cabal を Nix と組み合わせる自分好みの方法についてはまだ見つけられていません。こっちは長旅になりそうです。