いものやま。

雑多な知識の寄せ集め

GHCの使い方を調べてみた。(その8)

昨日は、GHCiでの型などの宣言と、型や識別子、モジュールの調査について説明した。

GHCiの基本的な使い方はこれでオシマイ。

一応、GHCiにはデバッガーの機能もあるようなのだけど、正直、Haskellの遅延評価の仕組みと相性が悪くて、使い物になってないと思う・・・
なので、この機能についてはパス。
Haskellでは、関数が純粋なことを使って、単体テストデバッグを行うのが基本なんだと思う)

今日は、GHCi環境のカスタマイズについて。

プロンプトのカスタマイズ

GHCiのプロンプトをカスタマイズしたい場合、:set promptコマンド、ならびに、:set prompt2コマンドを使う。
(後者は複数行入力のときのプロンプトをカスタマイズする)

Prelude> :set prompt "$ "
$ :set prompt2 "| "
$ :{
| let a = 1
|     b = 2
| in a + b
| :}
3
$ 

なお、プロンプトを指定する文字列で%sを使うと、インポートされているモジュールのリストに置換される。

$ :set prompt "(%s) "
(Prelude) import Control.Monad
(Prelude Control.Monad) 

プロンプトの設定を確認したい場合は、:show prompt:show prompt2を使う。

(Prelude Control.Monad) :show prompt
"(%s) "
(Prelude Control.Monad) :show prompt2
"| "

デフォルトの状態に戻したい場合には、:unset prompt:unset prompt2を使えばいい。

(Prelude Control.Monad) :unset prompt
Prelude Control.Monad> :unset prompt2
Prelude Control.Monad> 

プログラム名、引数の設定

プログラム名と引数は、それぞれSystem.Environment.getProgName関数とSystem.Environment.getArgs関数で取得できる。

これらの関数で戻ってくる値を設定したい場合、それぞれ:set progコマンド、:set argsコマンドを使う。

Prelude> :set prog "Test"
Prelude> System.Environment.getProgName
"Test"
Prelude> :set args "hoge" "huga"
Prelude> System.Environment.getArgs
["hoge","huga"]
Prelude> 

設定されているプログラム名、引数は、:show progコマンド、:show argsコマンドでも確認できる。

Prelude> :show prog
"Test"
Prelude> :show args
["hoge","huga"]
Prelude> 

型、経過時間などの表示

:set +tコマンドを使うと、変数に式を束縛したとき、その型が表示されるようになる。

Prelude> :set +t
Prelude> 1 + 2
3
it :: Num a => a
Prelude> let f x = x + 2
f :: Num a => a -> a
Prelude> 

また、:set +sコマンドを使うと、経過時間などが表示されるようになる。

Prelude> :set +s
Prelude> let a = 1
(0.00 secs, 515,320 bytes)
Prelude> a + 2
3
(0.00 secs, 1,587,120 bytes)
Prelude> :{
Prelude| let
Prelude|   fibo 1 = 1
Prelude|   fibo 2 = 1
Prelude|   fibo n = fibo (n - 2) + fibo (n - 1)
Prelude| :}
(0.00 secs, 1,540,936 bytes)
Prelude> :{
Prelude| let
Prelude|   fibo' n = fibo'_ n 1 1
Prelude|     where
Prelude|       fibo'_ 0 a _ = a
Prelude|       fibo'_ n a b = fibo'_ (n - 1) b (a + b)
Prelude| :}
(0.00 secs, 2,059,200 bytes)
Prelude> fibo 30
832040
(1.23 secs, 517,096,072 bytes)
Prelude> fibo' 30
1346269
(0.00 secs, 2,587,736 bytes)
Prelude> 

これらを元に戻すには、それぞれ、:unset +t:unset +sを使えばいい。

vi風のキーバインド

GHCiでvi風のキーバインドを使いたい場合、~/.haskelineに以下のように書く。

editMode: Vi

これでvi風のキーバインドになり、Escキーを押してコマンドモードに移行すれば、kやjで履歴を追ったり、hやl、b、wといった移動コマンドでカーソルの移動を行ったりすることが出来る。

なお、おそらく必要ないと思うんだけど、もしかしたらhaskelineパッケージを入れないといけないかもしれない。
その場合、次のように、Cabalを使ってhaskelineパッケージをインストールすればいい:

$ cabal install haskeline

.ghciファイル

GHCiは起動時に以下のファイルを探し、存在したものを以下の順番で読み込んですべて実行する。
(最初に見つかったものだけが実行されるわけではない)

  1. ./.ghci
  2. appdata/ghc/ghci.conf (appdataはシステム依存)
  3. ~/.ghc/ghci.conf
  4. ~/.ghci

これらのファイルを使って、GHCi環境のカスタマイズを行ったり、あるいは、毎回必要になるような処理を行うといい。

それにしても、この順番はどうなんだろう・・・

普通は、

  • グローバルな設定を行った後に、よりローカルな設定を行い、必要ならグローバルな設定を上書きする
  • ローカルな設定が存在するか確認し、存在すればそれを実行し、存在しなければよりグローバルな設定を探す(必要ならローカルな設定からグローバルな設定を読み込む)

のいずれかでデザインすると思うんだけど、上記の順番は

  1. フォルダローカルな設定
  2. グローバルな設定
  3. 個人ローカル(>フォルダローカル)な設定
  4. 同上(古風)

となっていて、順番がデタラメ。

見つかったものはすべて実行するというデザインなら、

  1. appdata/ghc/ghci.conf (appdataはシステム依存)
  2. ~/.ghc/ghci.conf
  3. ~/.ghci
  4. ./.ghci

という順番じゃないと、おかしい。

その他

他にも、マクロを定義したり、式の評価の出力を変更したり、ロードするときにオブジェクトファイルにコンパイルするように設定することも出来るみたい。
ただ、今回は省略。

今日はここまで!