pulpでPureScriptプロジェクトをビルドする

遅れてスンマセン http://qiita.com/advent-calendar/2014/purescript の5日目

pulpはpurescriptのビルドツール兼プロジェクト管理機能みたいなやつ。

[bodil/pulp](https://github.com/bodil/pulp "bodil/pulp")

purescriptのコマンド体系、色々難しくて、それをラップして僕みたいな雑な人間からも扱いやすくしてくれる


## インストール

Haskellとnodeのインストールは各自任せる

```
cabal install purescript
npm install pulp -g
```

```
~/s/pulp-test $ psc --version
0.6.1.1
```


どんなコマンドがあるかみてみる

```
~/s/pulp-test $ pulp -h
Usage: cyan <command> [options]

Options:

      --help -h Show this help message

    --command * [string]

--bower-file -b Read this bower.json file instead of autodetecting it [string]

--build-path -o Path for compiler output (default './build') [string]

      --main -m Application's entry point [string]

        --to -t Output file name for bundle (default stdout) [string]

    --transform Apply a Browserify transform [string]

   --source-map Tell Browserify to generate source maps [string]

     --watch -w Watch source directories and re-run command if something changes [boolean]

        --force For 'pulp init', overwrite any project found in the current directory [boolean]

  --optimise -O Perform dead code elimination when browserifying [boolean]


Available commands:

  init  - Generate an example PureScript project
  install       - Download and install project dependencies
  build         - Build the project
  test  - Run project tests
  browserify    - Produce a deployable bundle using Browserify
  run   - Compile and run the project
  docgen        - Generate project documentation
  psci  - Launch a PureScript REPL configured for the project
```

## pulp init で初期化


```
~/s/pulp-test $ pulp init
* Generating project skeleton in /Users/mizchi/sandbox/pulp-test

~/s/pulp-test $ ls
total 8
drwxr-xr-x   5 mizchi  staff   170B 12  6 16:53 .
drwxr-xr-x  19 mizchi  staff   646B 12  6 16:37 ..
-rw-r--r--   1 mizchi  staff   171B 12  6 16:53 bower.json
drwxr-xr-x   3 mizchi  staff   102B 12  6 16:53 src
drwxr-xr-x   3 mizchi  staff   102B 12  6 16:53 test
```

こんなディレクトリになってるはず

```
~/s/pulp-test $ tree
.
├── bower.json
├── src
│   └── Main.purs
└── test
    └── Main.purs

2 directories, 3 files
```


## pulp install

bower installのエイリアスっぽい


## ビルドする

`pulp build`コマンドを叩いてみるとoutputディレクトリができた

```
~/s/pulp-test $ pulp build
* Building project in /Users/mizchi/sandbox/pulp-test
* Build successful.

~/s/pulp-test $ tree output
output
├── Control.Monad.Eff
│   ├── externs.purs
│   └── index.js
├── Control.Monad.Eff.Unsafe
│   ├── externs.purs
│   └── index.js
├── Control.Monad.ST
│   ├── externs.purs
│   └── index.js
├── Data.Eq
│   ├── externs.purs
│   └── index.js
├── Data.Function
│   ├── externs.purs
│   └── index.js
├── Debug.Trace
│   ├── externs.purs
│   └── index.js
├── Main
│   ├── externs.purs
│   └── index.js
├── Prelude
│   ├── externs.purs
│   └── index.js
└── Prelude.Unsafe
    ├── externs.purs
    └── index.js
```

標準ライブラリ的なものが出力されてるのかな。

このままだと使いにくいので `pulp broserify` コマンドで一つにまとめてみる。

```
~/s/pulp-test $ pulp browserify --to all.js
* Browserifying project in /Users/mizchi/sandbox/pulp-test
* Building project in /Users/mizchi/sandbox/pulp-test
* Build successful.
* Browserifying...
* Browserified.
```

ここまでだったらまだnodeで動く気がするので、実行してみる

```
~/s/pulp-test $ node all.js 
Hello sailor!
```

ビンゴ


## pulp psci

このプロジェクトのリソースを読み込んだ状態で、インタラクティブシェルに入る


```
~/s/pulp-test $ pulp psci
 ____                 ____            _       _   
|  _ \ _   _ _ __ ___/ ___|  ___ _ __(_)_ __ | |_ 
| |_) | | | | '__/ _ \___ \ / __| '__| | '_ \| __|
|  __/| |_| | | |  __/___) | (__| |  | | |_) | |_ 
|_|    \__,_|_|  \___|____/ \___|_|  |_| .__/ \__|
                                       |_|        

:? shows help

Expressions are terminated using Ctrl+D
> :?
The following commands are available:

    :?              Show this help menu
    :i <module>     Import <module> for use in PSCI
    :b <module>     Browse <module>
    :m <file>       Load <file> for importing
    :q              Quit PSCi
    :r              Reset
    :s import       Show imported modules
    :s loaded       Show loaded modules
    :t <expr>       Show the type of <expr>
    :k <type>       Show the kind of <type>
> :i Main
Compiling Prelude
Compiling Prelude.Unsafe
Compiling Data.Function
Compiling Data.Eq
Compiling Control.Monad.Eff
Compiling Control.Monad.Eff.Unsafe
Compiling Control.Monad.ST
Compiling Debug.Trace
Compiling Main
Compiling Test.Main
> 
```

Mainがロードできた。


## 外部パッケージを読んでみる

bowerからpurescript-reactをいれてみる

[purescript-contrib/purescript-react](https://github.com/purescript-contrib/purescript-react "purescript-contrib/purescript-react")


```
bower install purescript-react --save
```

psciから呼べるか確かめてみる

```
Expressions are terminated using Ctrl+D
> :i React
Compiling React
Compiling React.DOM
> 
```

いけそう



サンプルコードを試す

```haskell
module Main where

import React
import React.DOM

hello = mkUI spec do
  props <- getProps
  return $ h1 [
      className "Hello"
    ] [
      text "Hello, ",
      text props.name
    ]

incrementCounter = do
  val <- readState
  writeState (val + 1)

counter = mkUI spec { getInitialState = return 0 } do
  val <- readState
  return $ p [
      className "Counter",
      onClick incrementCounter
    ] [
      text (show val),
      text " Click me to increment!"
    ]

main = do
  let component = div {} [hello {name: "World"}, counter {}]
  renderToBody component
```

buildしようとしたらコケた

```
~/s/pulp-test $ pulp build
* Building project in /Users/mizchi/sandbox/pulp-test
Reading ./output/Prelude/externs.purs
Reading ./output/Prelude.Unsafe/externs.purs
Reading ./output/Data.Function/externs.purs
Reading ./output/Data.Eq/externs.purs
Reading ./output/Control.Monad.Eff/externs.purs
Reading ./output/Control.Monad.Eff.Unsafe/externs.purs
Reading ./output/Control.Monad.ST/externs.purs
Reading ./output/Debug.Trace/externs.purs
Compiling React
Writing ./output/React/index.js
Writing ./output/React/externs.purs
Compiling React.DOM
Writing ./output/React.DOM/index.js
Writing ./output/React.DOM/externs.purs
Compiling Main
Error at src/Main.purs line 29, column 7: 
Error in declaration counter
Cannot unify Control.Monad.Eff.Eff with Prim.Function.
* ERROR: Subcommand terminated with error code 1
```

今ちょっとここを追う気力はない…が、まあなんかライブラリも呼べることがわかって満足した。あとは強い人達に任せます。