昨日はGHCiでのインポートについて説明した。
ただ、ロードとインポートの違いが分かりにくいので、今日はその補足。
ロードとインポートの違い
ロードとインポートの違いを一言で言い表すと、次のようになる:
- ロード
ファイルやパッケージからコードをメモリに読み込むこと。 - インポート
GHCiのスコープから関数などを見えるようにすること。
図にすると、次のようになる。
そして、インポートについては、アスタリスクつきのインポートとアスタリスクなしのインポートがあるけど、その違いは次のようになっている:
- アスタリスクつきのインポート
GHCiのスコープからモジュール内のすべてが見える。 - アスタリスクなしのインポート(普通のインポート)
GHCiのスコープからは、モジュールからエクスポートされたものだけが見える。
図にすると、次のようになる。
以下では、個別のケースについて、上記を確認してみる。
GHCiからロードを行ったときの挙動
最初に、Main.hsをロードするときの挙動を追ってみる。
Main.hsは以下のように、パッケージに含まれるSystem.EnvironmentとControl.Monad、それと、ファイルのFibo.hsをインポートしている。
ここでMain.hsをロードしてみる。
Prelude> :l Main
すると、、パッケージに含まれるSystem.EnvironmentとControl.Monadが必要になるので、自動的にロードされる。
そして、Fibo.hsがバイトコードにコンパイルされて、ロードされる。
最後に、Main.hsがバイトコードにコンパイルされて、ロードされる。
ここでさらに、Mainはアスタリスクつきで自動的にインポートされる。
そうすると、Mainで見えるものはGHCiのスコープからも見えるようになるので、FiboやSystem.Environment、Control.Monadのエクスポートされた関数などもGHCiのスコープで見えるようになる。
これで、プロンプトは`*Main> "に変わり、
*Main> :show modules Fibo ( Fibo.hs, interpreted ) Main ( Main.hs, interpreted ) *Main> :show imports :module +*Main -- added automatically *Main>
となる。
なお、上の状態でGHCiのスコープからFiboやSystem.Environment、Control.Monadのエクスポートされた関数などを見ることが出来るけれど、:show imports
にこれらが表示されないのは、あくまでこれらをインポートしているのはMain.hsであり、GHCiではないから。
GHCiからインポートを行ったときの挙動
次に、パッケージからData.Listをインポートしたときの挙動を追ってみる。
*Main> import Data.List
まず、パッケージに含まれるData.Listが必要になるので、自動的にロードされる。
そして、インポートされ、GHCiのスコープからエクスポートされた関数などが見えるようになる。
これで、プロンプトは"*Main Data.List> "に変わり、
*Main Data.List> :show imports import Data.List :module +*Main -- added automatically *Main Data.List>
となる。
:module
コマンドによる挙動
最後に、:module
コマンドでの挙動を追ってみる。
まず、Data.Listのインポートを外してみる。
*Main Data.List> :m -Data.List *Main>
これでData.ListがGHCiのスコープから見えなくなった。
そして、すべてのインポートを外してみる。
*Main> :m Prelude>
これでMainもGHCiのスコープから見えなくなったし、Mainから見えていたFiboやSystem.Environment、Control.MonadのエクスポートされたものもGHCiのスコープから見えなくなる。
ただし、ロードされたMainやFiboがアンロードされるわけではないので、メモリには残っている。
実際、:show modules
を実行してみると、次のようになる。
Prelude> :show modules Fibo ( Fibo.hs, interpreted ) Main ( Main.hs, interpreted ) Prelude>
ここから、Mainをインポートしてみる。
Prelude> :m Main Prelude Main>
すると、次のように、Mainがインポートされ、Mainのエクスポートされた関数など(この場合、Mainのトップレベルで定義されたものになるみたい)がGHCiのスコープから見えるようになる。
なので、次のように、main関数は実行できるけど、fibo関数などは見えないので使うことが出来ない。
relude Main> :main 10 [1,1,2,3,5,8,13,21,34,55] Prelude Main> fibo 10 <interactive>:103:1: Not in scope: ‘fibo’ Prelude Main>
最後に、Fiboをアスタリスクつきでインポートしてみる。
Prelude Main> :m +*Fibo *Fibo Main>
こうすると、Fiboで見えるものはGHCiのスコープから全部見えるようになるので、fibo関数はもちろん、fibo'関数も使えるようになる。
*Fibo Main> fibo 10 55 *Fibo Main> fibo' 10 1 1 55 *Fibo Main>
今日はここまで!