gitでローカルに取得したHaskellパッケージを使って、自作実行環境から使ってみる

# 初めての投稿

 [こちらの記事](http://qiita.com/lesguillemets/items/bf005952cf87480215c9)を参考に、Hackage公開ではないHaskellパッケージを利用して、動かしてみる。
とにかく、超初心者だったけれど、stackと、それが提供してくれるデフォルトプロジェクトの作成方法、そこに出来上がるもの、.cabalファイルってどれ？ Main.hsってどこ？などについての知識を仕入れた段階で挑戦。

# 環境

Ubuntu　(使い慣れていません…)

# 準備

- Stackをインストールしておく。
- ライブラリのインストール(いつやったのか、覚えていない)


```bash
sudo apt install liblapack-dev libblas-dev
```

# 使いたいけれど、Hackageにないパッケージの入手

Hackageにあれば、.cabalファイルに書き込めば stack コマンドで取れるけれど、そうは行かないので、ローカルに取ってきて、そのローカルに置かれたパッケージを.cabalに指定することにする

## git でパッケージを取得

~/test/ 以下で作業することとする

```bash
git clone https://github.com/adscib/monad-bayes
```

これで、~/test/monad-bayes/

ができる。この中に、monad-bayes.cabalファイルもあれば、src ディレクトリ、app ディレクトリもある。

この monad-bayes.cabalには山のように必要なモジュールを取るための情報が書かれている。

~/test/monad-bayes/
以下で次をやる。

```bash
stack haddock
stack haddock --open
```
これで、monad-bayesパッケージの情報をブラウザで見られるようになる。

# 実行環境の準備
自分でmonad-bayesパッケージを使って実行する環境を作る。

これも、stackを使って作る。

~/test/ で

```bash
stack new mbplay
```
する。
~/test/mbplay/
ディレクトリができ、その下に、
mbplay.cabalファイルができ、

~/test/mbplay/app/ 以下に、Main.hsができ
~/test/mbplay/src/ 以下に、Lb.hs ができる。

Main.hsは実行可能ファイルを作らせる「根っこ」のファイル。

srcディレクトリに、このmbplayプロジェクトのためのモジュールファイルを置くことにする。

## mbplayのstack.yaml ファイルの書き換え

今、このプロジェクトのディレクトリは
~/test/mbplay/　であって、使いたいパッケージは
~/test/monad-bayes/ にあるので、

相対パスで、monad-bayesパッケージの頂上のディレクトリを指定する

```haskell
packages:
- '.'
- location:
    "../monad-bayes" # さっき clone したディレクトリ
  extra-dep: true    # 依存先（本体の一部じゃなくて）として扱ってもらう
```
## mbplay のmbplay.cabal ファイルの書き換え

このプロジェクトで、ローカルに置いたmonad-bayes パッケージを使いたいので、それを指定する。

使う場所は、Main.hsかもしれないし、ローカルモジュールたちかもしれないので、mbplay.cabalファイルのそれぞれを管轄する部分にmonad-bayesを指定する。

~/test/mbplay/src/　以下のローカルモジュールのファイル内でimportできるようにする。

```haskell
library  
  hs-source-dirs:      src
  exposed-modules:     Lib
  build-depends:       base >= 4.7 && < 5
                     , monad-bayes
  default-language:    Haskell2010
```
~/test/mbplay/app/　以下にあるMain.hsでもimportできるようにする。

```haskell
executable mbplay-exe
  hs-source-dirs:      app
  main-is:             Main.hs
  ghc-options:         -threaded -rtsopts -with-rtsopts=-N
  build-depends:       base
                     , mbplay
                     , monad-bayes
  default-language:    Haskell2010
```
## ここまでがうまく行っているかを確認

### その１
この段階では、mbplayプロジェクトのMain.hsは、その中から、~/test/mbplay/Lib.hs をimportして、その中の関数を実行するようにできている。

~/test/mbplay/

以下で

```bash
stack install
```
とすると
mbplay-exe　という実行可能ファイルができるが、まず、それをやってみる。

```bash
mbplay-exe
```

とやると、コンソールに"someFunc"という文字列が現れる。

### その２
ついで、~/test/mbplay/Lib.hs
を次のように書き換える。

```haskell
module Lib (someFunc) where
import Control.Monad.Bayes.Simple
```
このControl.Monad.Bayes.Simple は、今、使いたいと思っているmonad-bayesパッケージの中にあるものなので、このimportがうまく行けば、パッケージ利用環境はOKと解る。

この状態で

```bash
stack build
```

して、無事にコンパイルが終わればOK。

# monad-bayesパッケージを利用

さて、本番。

monad-bayesパッケージを使うために、以下をする。

## 自作モジュールを作る
monad-bayesパッケージでは、

~/test/monad-bayes/test/
というディレクトリがあり、その中にいくつかのhoge.hsファイルがある。
これらは、~/test/monad-bayes/test/src/にあるわけではないので、モジュールとして参照できない(多分)。

なので、この~/test/monad-bayes/test/models/ 以下に置かれた Dice.hsというファイルを使った処理をmbplayの方でやって見ることにする。

~/test/mbplay 以下にいるとして、次のようなコマンドで

~/test/monad-bayes/models/Dice.hs
を
~/test/mbplay/src/Dice.hs としてコピーする。

```bash
# mbplay に今いるとして
cp ../monad-bayes/models/Dice.hs src/
```

この~/test/mbplay/src/Dice.hs を使うために、~/test/mbplay/mbplay.cabalを書き換える。
srcディレクトリの下にあるモジュールファイルのうち、使うのはDice.hsであって、Lib.hsでは無いので、exposed-modulesを書き換える。

```haskell
library  
  hs-source-dirs:      src
  exposed-modules:     Dice
  build-depends:       base >= 4.7 && < 5
                     , monad-bayes
  default-language:    Haskell2010
```
## Main.hsを書き換える

さて。
Dice.hsを利用した処理を書く。
Dice.hsを使いつつ、それ以外にもいくつかのモジュールが必要でそれをimport指定しながら、

20個のサイコロを振って、その目の和を取ること、5000試行。

その結果をresultsに入れた後、
値ごとにソートして、隣同士で同じ値のものをグループ化して、その長さを求め、ヒストグラム様標準出力をさせている。

```haskell
module Main where

import Dice
import Control.Monad.Bayes.Sampler

import Data.List (group, sort)
import Control.Monad (replicateM)

main :: IO ()
main = do
    results <- sampleIO . replicateM 5000 $ dice 20
    mapM_ putStrLn . hist . map length . group . sort $ results

-- create a very basic histogram. 
-- `div` 2 . (+1) is just there to make the bars shorter.
hist :: [Int] -> [String]
hist = map (flip replicate '#' . (`div` 2) . (+1))
```


# 実行してみよう
~/test/mbplay/

にて

```bash
stack build
stack exec mbplay-exec
```
# 練習を兼ねて少し改変
引数をとって、サイコロの数、試行回数、描出ヒストグラムの打点スケール、以上３つを指定するようにする

getArgsで取り込んだargs の0,1,2番目の要素をそれぞれInt型でnarg0,narg1,narg2に持たせる。

```haskell
module Main where

import Dice
import Control.Monad.Bayes.Sampler

import Data.List (group, sort)
import Control.Monad (replicateM)

import System.Environment
import System.IO

main :: IO ()
main = do
    args <- getArgs
    let narg0 = read (args !! 0) :: Int
    let narg1 = read (args !! 1) :: Int
    let narg2 = read (args !! 2) :: Int
    results <- sampleIO . replicateM narg0 $ dice narg1
    --results <- sampleIO . replicateM 5000 $ dice 20
    --mapM_ putStrLn . hist . map length . group . sort $ results
    mapM_ putStrLn . (hist2 narg2) . map length . group . sort $ results

-- create a very basic histogram. 
-- `div` 2 . (+1) is just there to make the bars shorter.
hist :: [Int] -> [String]
hist = map (flip replicate '#' . (`div` 2) . (+1))

hist2 :: Int -> [Int] -> [String]
hist2 x = map (flip replicate '#' . (`div` x) . (+1))
```

```bash
stack build
stack exec mbplay-exe 100000 10 200
```