Haskellでちょっとしたスクリプトを書く
Haskellで本格的に開発する際はcabalなりstackなりでプロジェクトを作るわけですが、ファイル一つで済むような(書き捨て)スクリプトをHaskellで書きたい場合があります。
依存関係のないスクリプトであれば、普通にファイルを作って runghc
/runhaskell
すれば良いでしょう。しかし、Haskellには標準ライブラリー(base
)以外にも「準標準」と呼べる外部のライブラリーが多数あり(例:bytestring
, text
, vector
)、それらに明示的に依存することは runghc
ではできません。
そこで使えるのが、cabal scriptやstack scriptと呼ばれる機能です。
cabal script
cabal run
コマンドを使うと、ファイル中に {- cabal:
形式の特殊なコメントを含むHaskellコードをその場でビルドして実行することができます。
例:
#!/usr/bin/env cabal
{- cabal:
build-depends: base, bytestring ^>= 0.11.3.1
-}
import qualified Data.ByteString.Char8 as BS
main = BS.putStrLn (BS.pack "Hello world!")
実行例(cabal-install 3.8の場合):
$ cabal run hellocabal.hs
Hello world!
$ chmod +x hellocabal.hs
$ ./hellocabal.hs
Hello world!
{- cabal:
はその行に単独で存在する必要があります。
shebangは、 cabal run
経由で実行する場合は必要ありません。
cabal scriptはcabal-install 3.8で色々強化されました。ビルド時のメッセージが表示されなくなったり、ビルド結果のキャッシュが実装されたり、 {- project:
が実装されたり、といった具合です。
{- project:
を使うと cabal.project
に相当する内容を書けます:
#!/usr/bin/env cabal
{- cabal:
build-depends: base, bytestring ^>= 0.11.3.1
-}
{- project:
with-compiler: ghc-9.4.3
-}
import qualified Data.ByteString.Char8 as BS
main = BS.putStrLn (BS.pack "Hello world!")
stack script
stackでもスクリプトを実行できます。むしろstackの方が元ネタで、cabal scriptが後発です。
- The script interpreter and stack script command — User's guide (introductory) - The Haskell Tool Stack
- script interpreter + stack script でスクリプティング!
例:
#!/usr/bin/env stack
-- stack script --resolver nightly-2022-11-08 --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です。
コードを貼るときに依存関係を明示するのに使う
GHCのバグ報告の際は報告文の中に再現コードを貼り付けることが多いです。その際、cabal script形式のコメントで依存関係を明示することができます。.cabal
ファイルを別途貼り付けるのに比べて、コピペの回数が減ります。
例:
歴史
歴史的にはstack scriptの方が古く、cabal scriptは2018年ごろに実装された比較的新しい機能です。
stackのscript interpreterは0.1.2.0, stack script
は1.4.0からの機能らしいです。
参考:
Discussion