LoginSignup
18
5

More than 5 years have passed since last update.

Stack (Haskell): Could not find moduleと言われたときの対処 2018年春版

Last updated at Posted at 2018-04-25

haskell入門 関数型プログラミング言語の基礎と実践』を読みながら写経をすると、たまにGHCからCould not find moduleと怒られるときがあります。

これは「モジュールが見つからない」という意味なので、そのモジュールが入ったパッケージを入れる必要があります。

しかし、パッケージの入れ方は複数あり、古いやり方・新しいやり方があるようです
(新規プロジェクトや特にこだわりが無い場合は、「新しいやり方」でOKです)

hogeというプロジェクトを新規作成します。

$ stack new hoge

ここでモジュール Data.ByteString.Char8 を使いたい、とします。

stack newした直後だと、Preludeにないモジュール利用可能なパッケージに含まれないモジュール(Prelude以外にもいくつかあります)をimportするとCould not find moduleエラーが出てきます。

$ stack ghci
*Main> import Data.ByteString.Char8
(中略)
<no location info>: error:
    Could not find module ‘Data.ByteString.Char8’
    It is not a module in the current program, or in any known package.

Data.ByteString.Char8モジュールを使うためには、bytestringパッケージが必要です。

このbytestringパッケージを指定する方法をこれから2つ、「古いやり方」と「新しいやり方」として紹介します。

古いやり方: 直接 hoge.cabal に書く

プロジェクトの中に(パッケージ名).cabalというファイルがあるはずです。
例えば、stack new hogeでプロジェクトを作れば、hoge.cabalがあるはずです。

そこに、必要なパッケージをexecutable hoge-exeの部分に直接書くと、とりあえずビルドは通ります。

(今は array, bytestring, containers の3つのパッケージを入れることにしましょう)

executable hoge-exe
  main-is: Main.hs
  hs-source-dirs:
      app
  ghc-options: -threaded -rtsopts -with-rtsopts=-N
  build-depends:
    base >=4.7 && <5
    , array
    , bytestring
    , containers

しかし、build-dependsは他の項目にもあります(library,test-suite)。
すべてを書き換えるのは面倒です。

新しいやり方: package.yamlに書く

現在(2018年春)は、必要なパッケージをStackのpackage.yamlに書く方がよいようです。
この設定を元に、hoge.cabal自動生成(更新)されるようになっています。

これからのHaskellプロジェクトではcabalではなくpackage.yaml(hpack)を使いましょう - ncaqでは、hoge.cabalpackage.yamlの関係が次のように例えられています。

JavaScriptに対するAltJSのようなものです

package.yamlでは次のように書きます。

dependencies:
- base >= 4.7 && < 5
- array
- bytestring
- containers

この設定でstack buildすると、hoge.cabalが自動生成(更新)されます。

library
  hs-source-dirs:
      src
  build-depends:
      array
    , base >=4.7 && <5
    , bytestring
    , containers
(中略)
executable hoge-exe
  main-is: Main.hs
  hs-source-dirs:
      app
  ghc-options: -threaded -rtsopts -with-rtsopts=-N
  build-depends:
      array
    , base >=4.7 && <5
    , bytestring
    , containers
    , hoge
(中略)
test-suite hoge-test
  type: exitcode-stdio-1.0
  main-is: Spec.hs
  hs-source-dirs:
      test
  ghc-options: -threaded -rtsopts -with-rtsopts=-N
  build-depends:
      array
    , base >=4.7 && <5
    , bytestring
    , containers
    , hoge

必要なパッケージが、hoge.caballibrary, executable, test-suiteの3つに反映されました。
便利ですね。

注意: 標準以外のテンプレートを使っている場合

stack newでは、プロジェクトのテンプレートを指定できます。
これを使うと、たとえば「Yesod用のプロジェクト」をコマンド一発で新規作成できます。
(標準で使用できるテンプレートはstack templatesで一覧を見られます)

しかし、標準以外のテンプレートにはpackage.yamlが存在しない場合もあります。
その場合はsimple-hpackのように、末尾に-hpackがついたテンプレートが使えるようです。

$ stack new hoge simple-hpack

参考: hpack と hspec に対応した stack templates - Qiita

補足: CabalとStackの関係

Stackがなかったその昔、パッケージの管理はすべてCabalの仕事でした。
しかし、依存関係が複雑になりすぎて「Cabal hell (dependency hell)」とまで呼ばれた時代でした。

現在(2018年春)はStackageが、「依存関係に問題のないCabalパッケージ一式」(スナップショット)をまとめてくれています。

Stackの役割はたくさんありますが、その一つは「スナップショットの範囲で使えるCabalパッケージ」を使ってプロジェクトをビルドすることです。

Stackのプロジェクトは、Cabalのパッケージを包括するものです。
(詳細: stack.yaml vs cabal package files - The Haskell Tool Stack)

現在ではcabalコマンドを直接触ることは少なくなりましたが、Stackで使われているパッケージの仕組みはCabalを流用しています。

たとえば、stack.yamlを読むと、resolver: lts-11.6という項目があります。
これは「Stackageのスナップショット「LTS Haskell 11.6 (ghc-8.2.2)」にあるパッケージであれば、すぐに使える」という意味になります。
(ただし、baseパッケージ以外は、上記の方法で使うパッケージを教えてあげる必要があります)

Stackは指定されたスナップショット(resolver)を原則として参照します。つまり次のようにパッケージを探します。

  1. スナップショットにあるパッケージは、Stackageで指定された通りのバージョンを自動的に指定する
  2. スナップショットにないパッケージは、外部の依存パッケージを(バージョン番号込みで)開発者に指定してもらう
    • stack.yamlextra-deps
    • 例: acme-missiles-0.3

Could not find moduleと言われたら、まずはStackageで検索して、(1.のように)使われているスナップショット内のパッケージ名を調べましょう。
ただし、たまにStackageにないパッケージもあります。その場合は、(2.のように)extra-depsでパッケージを明示的に指定しましょう。

以上です。

18
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
5