ClojureでREPL駆動開発を始めよう

先日、Opt Technologiesの社内勉強会で [*Practical REPL-driven Development with Clojure*](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure) と題してClojureとREPL駆動開発の入門的な発表をしたので、その内容を簡単にご紹介します。

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-1-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure)

# 1. Clojure Quick Intro

スライド pp. [4](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/4)-[8](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/8)

極めて簡潔なClojure入門

## Clojureとは

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-5-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/5)

## Clojureのリテラル(+α)

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-6-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/6)

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-7-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/7)

## Clojureのシンタックス

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-8-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/8)

# 2. Leiningen

ビルドツール[Leiningen](https://leiningen.org/)の使い方

スライド pp. [9](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/9)-[17](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/17)

## 基本的な `lein` タスク

### `lein repl`: REPLを起動

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-10-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/10)

### `lein new <template name> <project name>`: テンプレートを指定してプロジェクト生成

例えば

```sh
$ lein new app clj-demo
```

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-11-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/11)

### `lein run`: `-main` 関数を実行

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-13-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/13)

### `lein test`: テストを実行

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-15-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/15)

### `lein uberjar`: jarファイルを作成

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-17-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/17)

# 3. Clojure REPL

Clojure REPLの使い方

スライド pp. [18](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/18)-[24](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/24)

## REPLで利用可能な主なユーティリティ

### [doc](https://clojure.github.io/clojure/clojure.repl-api.html#clojure.repl/doc): ドキュメントを出力

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-20-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/20)

### [source](https://clojure.github.io/clojure/clojure.repl-api.html#clojure.repl/source): ソースコードを出力

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-21-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/21)

### [*1](https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/*1), [*2](https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/*2), [*3](https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/*3): 直前の評価結果を保持する変数

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-22-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/22)

### [*e](https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/*e): 直前の例外を保持する変数 (cf. [pst](https://clojure.github.io/clojure/clojure.repl-api.html#clojure.repl/pst))

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-23-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/23)

### 検索系

- [find-doc](https://clojure.github.io/clojure/clojure.repl-api.html#clojure.repl/find-doc)

- [apropos](https://clojure.github.io/clojure/clojure.repl-api.html#clojure.repl/apropos)

- [javadoc](https://clojure.github.io/clojure/clojure.java.javadoc-api.html#clojure.java.javadoc/javadoc)

# 4. Lisp Editing

Lisp編集のためのエディタプラグインの使い方

スライド pp. [25](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/25)-[60](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/60)

## [Parinfer](http://shaunlebron.github.io/parinfer/)

*Indent* mode ではインデント編集時に括弧を、 *Paren* modeでは括弧編集時にインデントを自動調整するプラグイン

### [Atom](https://atom.io/)に[Parinfer](https://atom.io/packages/parinfer)を設定した環境での操作例(抜粋)

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-34-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/34)

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-35-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/35)

↑では、改行後に書き始めるインデント位置によって自動的に閉じ括弧の位置が調整されている(*Indent* mode)。

## [ParEdit](https://www.emacswiki.org/emacs/ParEdit)

特殊なキーバインドを利用して括弧とインデントを半自動的に調整するプラグイン

### [Spacemacs](http://spacemacs.org/)に[ParEdit](https://www.emacswiki.org/emacs/ParEdit)を設定した環境での操作例(抜粋)

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-58-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/58)

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-59-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/59)

↑では、 `M-(` (メタキーと `(` の同時入力)という特殊なキーバインドで直後の式を丸括弧で囲んでいる。

# 5. REPL-driven Development in practice

Clojure Koansと4ClojureというClojureチュートリアルを題材に、REPL駆動開発してみる

スライド pp. [61](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/61)-[96](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/96)

## コースA: [Clojure Koans](http://clojurekoans.com/)

禅の公案問答のごとく(?)ひたすら穴埋め問題に取り組みながらClojureの基礎が学べるチュートリアル

### 1. リポジトリをcloneする

```sh
$ git clone git://github.com/functional-koans/clojure-koans.git
```

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-64-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/64)

### 2. koan(公案)プログラムを実行する

```sh
$ cd clojure-koans/
$ lein koan run
```

実行すると、アサーションに失敗する。

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-65-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/65)

### 3. ソースファイルをエディタで開く

例えば

```sh
$ emacs src/koans/01_equalities.clj
```

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-66-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/66)

### 4. Clojure REPLを起動する

Spacemacs/Emacs + [CIDER](https://cider.readthedocs.io/en/latest/)プラグインなら `cider-jack-in` コマンド(`, '`, `M-RET '` or `C-c M-j`)

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-67-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/67)

### 5. ソース上の式を評価しながら穴埋め問題を解いてアサーションを通るようにする

#### ソースバッファ上でインライン評価

Spacemacs/Emacsなら `cider-eval-last-sexp` コマンド(`, e e`, `M-RET e e`, `C-x C-e` or `C-c C-e`)など

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-68-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/68)

#### ソースバッファからREPLバッファに送って評価

Spacemacsなら `cider-send-last-sexp-to-repl` コマンド(`, s e`, `M-RET s e`)など

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-71-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/71)

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-72-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/72)

### 6. 変更を保存してmeditation(瞑想/坐禅)の結果を確認する

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-77-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/77)

## コースB: [4Clojure](https://4clojure.oxal.org/)

Clojureの基礎は習得済みのプログラマ向けの問題集

### 1. エディタでClojureのバッファを開く

例えば

```sh
$ emacs clj-demo/src/clj_demo/4clojure/problem22.clj
```

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-79-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/79)

### 2. Clojure REPLを起動する

Spacemacs/Emacs + [CIDER](https://cider.readthedocs.io/en/latest/)プラグインなら `cider-jack-in` コマンド(`, '`, `M-RET '` or `C-c M-j`)

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-80-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/80)

### 3. 例として[Problem #22](https://4clojure.oxal.org/#/problem/22)に取り組んでみる

シーケンスの要素数を返す関数を書く問題(標準関数 `count` は使わない)。

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-81-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/81)

### 4. 関数を書いてみる

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-82-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/82)

### 5. 書いた関数の動作確認をする

#### ソースバッファ上でインライン評価

Spacemacs/Emacsなら `cider-eval-last-sexp` コマンド(`, e e`, `M-RET e e`, `C-x C-e` or `C-c C-e`)など

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-83-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/83)

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-84-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/84)

#### ソースバッファからREPLバッファに送って評価

Spacemacsなら `cider-send-last-sexp-to-repl` コマンド(`, s e`, `M-RET s e`)など

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-89-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/89)

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-90-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/90)

[![slide](http://image.slidesharecdn.com/practical-rdd-171013044057/95/slide-91-1024.jpg)](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/91)

### 6. [問題ページ](https://4clojure.oxal.org/#/problem/22)に解答を貼り付けて実行してみる

問題ページで実行可能な形式にするには、以下のように元の関数定義の `defn` を `fn` に置き換えると良い(※ `defn` 式の評価結果は関数として呼び出し可能([Var](https://clojure.org/reference/vars))なので `defn` のままでも一応動作する)。

```clj
(fn my-count [coll]
  (reduce (fn [n _] (inc n))
          0
          coll))
```

# Further Reading

- スライド pp. [98](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/98)-[104](https://www.slideshare.net/KentOhashi/practical-repldriven-development-with-clojure/104)

## エディタプラグイン/設定

- [Clojure/ClojureScript関連リンク集 > Clojure開発全般](https://qiita.com/lagenorhynque/items/68c314c288b75a9492ba#clojure%E9%96%8B%E7%99%BA%E5%85%A8%E8%88%AC)
- [Clojure開発環境での基本操作まとめ: Spacemacs, IntelliJ IDEA (Cursive), VS Code (Calva), Vim (vim-iced), rebel-readline](https://qiita.com/lagenorhynque/items/0b52575e90bad563e4bd)
- [Clojureで快適なREPL駆動開発のために"reloaded workflow"を実践しよう](https://qiita.com/lagenorhynque/items/a752ffae490e83ebe70d)

## Lisp編集プラグイン

- [Clojure/ClojureScript関連リンク集 > Lisp編集支援](https://qiita.com/lagenorhynque/items/68c314c288b75a9492ba#lisp%E7%B7%A8%E9%9B%86%E6%94%AF%E6%8F%B4)

## REPL駆動開発

- [Clojure/ClojureScript関連リンク集 > REPL駆動開発](https://qiita.com/lagenorhynque/items/68c314c288b75a9492ba#repl%E9%A7%86%E5%8B%95%E9%96%8B%E7%99%BA)