haskell-stackを使ってxmonadをビルドする（外部モジュールが使えたりする）

# 旧タイトル: xmonad.hsでモジュール分割をする
　この記事はxmonad用に書かれていますが、xmonadやyiエディタのような、そもそもmainを自前で書くhaskell-stack対応のHaskellプロジェクトなら、同じ方法で解決できます。


# 目的
```
~/.xmonad
|- xmonad.hs
|- XMonadConfig
   |- Types.hs
```

　こんな感じのディレクトリ構成とし、`~/XMonadConfig/Types.hs`(`XMonadConfig.Types`モジュール)はxmonad.hsからimportされているとして、xmonad.hsをコンパイルする。


# 問題
　xmonad.hsは[xmonad](http://xmonad.org)の設定ファイルですが、通常通り`xmonad --recompile`をするとxmonadコマンド越しでのxmonad.hsのコンパイルになってしまうので、上記の`XMonadConfig.Types`モジュールはxmonadコマンドに読み込まれず、コンパイルエラーになります。


# 解決方法
　xmonad.hsを[haskell-stack](https://docs.haskellstack.org/en/stable/README/)プロジェクトにし、プロジェクトのビルド結果で`xmonad-config`という実行可能バイナリがインストールされるようになります。

# 解決
## xmonad-configプロジェクトの作成
```shell
$ cd /tmp
$ stack new xmonad-config simple
$ mv ~/.xmonad/xmonad.hs xmonad-config && rm -rf ~/.xmonad
$ mv xmonad-config ~/.xmonad
$ cd ~/.xmonad
```

## xmonad-config.cabalを書き換える
```
$ ls xmonad-config.cabal
xmonad-config.cabal
$ vim xmonad-config.cabal
```

xmonad-configの内容

```xmonad-config.cabal
name:                xmonad-config
version:             0.1.0.0
synopsis:            Simple project template from stack
description:         Please see README.md
homepage:            https://google.co.jp
license:             BSD3
license-file:        LICENSE
author:              your_name
maintainer:          your_mail_address@example.co.jp
copyright:           your_name
category:            Simple
build-type:          Simple
cabal-version:       >=1.10

executable xmonad-config
  hs-source-dirs:      .
  main-is:             xmonad.hs
  default-language:    Haskell2010
  other-modules:       XMonadConfig.Types
  build-depends:       base >= 4.7 && < 5
                     , xmonad
```

ここで、`xmonad-contrib`や`xmonad-extras`を使いたい場合は、build-dependsに追加しておきます。

　XMonadConfig/{Actions,Types}.hsを作成します。
```
$ mkdir XMonadConfig
$ vim XMonadConfig/Types.hs
```

```haskell:~/.xmonad/XMonadConfig/Types.hs
module XMonadConfig.Types
  ( Workspaces
  ) where

-- | The another expression of XMonad.Config.XConfig.workspaces
type Workspaces = [String]
```

## xmonad-configのインストール (プロジェクトのビルド)

- ※ 下記コードはイメージです

```
$ cat xmonad.hs
import XMonadConfig.Types (Workspaces)
import XMonad

main :: IO ()
main = do
  xmonad $ desktopConfig
    { terminal           = "termite"
    , modMask            = superMask
    , workspaces         = myWorkspaces
    }

myWorkspaces :: Workspaces
myWorkspaces = map show [1..4]

$ stack install
Copying from /home/user_name/.xmonad/.stack-work/install/x86_64-linux/lts-7.14/8.0.1/bin/xmonad-config to /home/user_name/.local/bin/xmonad-config

Copied executables to /home/user_name/.local/bin/:
- xmonad-config
```


# 適用
　xmonad-configが生成されましたので、目的自体は達成です。  
.xinitrcあたりに、xmonadの代わりとしてxmonad-configを書いておきましょう。

```shell
exec ~/.local/bin/xmonad-config
```


# xmonad --recompileについて
　[このissue](https://github.com/commercialhaskell/stack/issues/710)に、stackを使って`xmonad --recompile`をする方法が書かれています。
以下の手順で、有効にすることができます。

## 1. ~/.xmonad/buildを作成する

```build:sh
#!/bin/bash
cd ~/.xmonad
stack build
```

## 2. stackに依存パッケージの位置を伝える

### ローカルに落とす場合

　この手順は…要はstackが直接、依存パッケージを参照できればいいので、stack.yamlにgithubリモートリポジトリのURIを教えてあげればいいのかもしれないけど、どうなんでしょう。

- - -

- `$ git submodule add https://github.com/xmonad/xmonad` or
- `$ git submodule add https://github.com/xmonad/xmonad-contrib` など（xmonad-configをgitで管理していない場合など、cloneしてもいい）

- stack.yamlを編集する
    - `stack solver --update-config`がよしなにやってくれるはず

僕の環境では、以下のようになりました！

```stack.yaml:yaml
flags:
  xmonad-extras:
    with_hint: false
    with_mpd: false
  xmonad-contrib:
    use_xft: false
extra-package-dbs: []
packages:
- '.'
- xmonad/
- xmonad-contrib/
- xmonad-extras/
extra-deps:
- X11-1.8
- alsa-core-0.5.0.1
- alsa-mixer-0.2.0.3
- xmonad-0.13
resolver: lts-7.14
```

　これで`xmonad-config --recompile`を行った際に`stack build`を行ってくれるようになります。