Haskellでちょっとしたスクリプトを書く
記事として公開しました:
Haskellで本格的に開発する際はcabalなりstackなりでプロジェクトを作るわけですが、ファイル一つで済むような(書き捨て)スクリプトをHaskellで書きたい場合があります。
依存関係のないスクリプトであれば、普通にファイルを作ってrunghc/runhaskellすれば良いでしょう。しかし、Haskellには標準ライブラリー(base)以外にも「準標準」と呼べる外部のライブラリーが多数あり(例:bytestring, text, vector)、それらに明示的に依存することはrunghcではできません。
そこで使えるのが、cabal scriptやstack scriptと呼ばれる機能です。歴史的にはstack scriptの方が古く(いつ?)、cabal scriptは2018年ごろに実装された比較的新しい機能です。
cabal script
cabal v2-run
コマンドを使うと、ファイル中に {- cabal:
形式の特殊なコメントを含むHaskellコードをその場でビルドして実行することができます。
例:
#!/usr/bin/env cabal
{- cabal:
build-depends: base, bytestring ^>= 0.11.3.0
-}
import qualified Data.ByteString.Char8 as BS
main = BS.putStrLn (BS.pack "Hello world!")
実行例:
$ cabal v2-run hellocabal.hs
…略…
Hello world!
$ chmod +x hellocabal.hs
$ ./hellocabal.hs
…略…
Hello world!
{- cabal:
はその行に単独で存在する必要があります。
shebangは、 cabal v2-run
経由で実行する場合は必要ありません。
stack script
- script interpreter - User guide - The Haskell Tool Stack
- script interpreter + stack script でスクリプティング!
例:
#!/usr/bin/env stack
-- stack script --resolver lts-18.28 --package bytestring --package vector
import qualified Data.ByteString.Char8 as BS
import qualified Data.Vector as V
main = do BS.putStrLn (BS.pack "Hello world!")
print (V.sum (V.fromList [1..100]))
実行例:
$ stack hellostack.hs
Hello world!
5050
$ chmod +x hellostack.hs
$ ./hellostack.hs
Hello world!
5050
stackへのオプションを指定する行はshebangを除いた最初の行(shebangがあれば2行目、shebangがなければ1行目)から始まる必要があります。{- -}
形式のコメントを使うことで複数行にわたって記述できます。
--package
を全く指定しなかった場合は、import
の内容から推測してくれます。
shebangは、stack
経由で実行する場合は必要ありません。
利用例
ちょっとしたスクリプトとして使う
例:https://github.com/minoki/icfpc2006/blob/master/extract-CBV.hs
bytestringとJuicyPixelsに依存するcabal script。
コードを貼るときに依存関係を明示するのに使う
例:Misleading GHC error when function is not in scope (#16491) · Issues · Glasgow Haskell Compiler / GHC · GitLab
GHCのバグ報告の再現コードが外部ライブラリーに依存する際にそれを明示するために使う。人間にとっても読める。