Windows+IntelliJ IDEAにClojureインストールしてJavaと相互呼び出しするまで

最近関数型言語の Immutable な世界の安心感にはまってしまい、JVM で動く LISP である Clojure にも手を出してしまいました。

Windows でのインストールや Java との呼び出しで微妙にハマったのでメモしておきます。

JDK 8 はインストール済みです。

# leiningen のインストール

Clojure は [Leiningen](http://leiningen.org/) というツールと合わせて使うのが一般的なようです。

Java でいう maven と似たようなツールです。

[leiningen-win-installer](http://leiningen-win-installer.djpowell.net/) というものがあるのですが、ここは本家  [Leiningen](http://leiningen.org/) から lein.bat をダウンロードしました。

これを好きなパスに配置して PATH を通します。

``lein self-insall`` を実行すると、 wget がないと叱られます。

 [GNU Wget 1.16.1 for Windows](https://eternallybored.org/misc/wget/) からバイナリを取得してこちらもパスに通したところ、無事成功。

``c:\Users\<自分のホーム>\.lein\`` 配下に関連ファイルがダウンロードされました。

# REPL を起動

```
> lein repl

....(省略)...

REPL-y 0.3.5, nREPL 0.2.6
Clojure 1.6.0
Java HotSpot(TM) 64-Bit Server VM 1.8.0-b132
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

user=> '(1 2 3)
(1 2 3)
user=> ((fn [x y] (+ x y)) 1 2)
3
```

# IntelliJ IDEA で Clojure を使う

せっかく leiningen が使えるようになったところなのですが、最近 Eclipse から乗り換えかけている [IntelliJ IDEA](https://www.jetbrains.com/idea/) で Clojure のコードを書いてみたくなったのでこちらにも環境を作ります。

* Version 14 の Community Edition をインストールしておきます。
* IntelliJ を起動し、File -> Settings で開く画面から Plugins を選びます。
* Install JetBrains Plugin.. で開く画面から clojure と入力すると La Clojure というプラグインが出てくるので、インストールして IntelliJ を再起動します。
* New Project で Java を選ぶと、Addtional Libraries and Frameworks に Clojure が表示されるので、チェックしてプロジェクトを作成。
* ``src`` 配下に new メニューから Clojure File を選んで Hello というモジュールを作成。

```
(print "Hello!")
```

Hello.clj を右クリックからの Run で無事実行できました。

### 追記: Cursive プラグイン

* koji_yusa さんから [Cursive](https://cursiveclojure.com/userguide/) プラグインをおすすめいただきました。ありがとうございます！
* まだガッツリ使っていないので差分はわからないのですが、メンテナンスされているのはこちらとのことです。確かに La Clojure は Clojure のバージョンが古かったりしますね



# Clojure から Java のコードを実行する

Java との相互呼び出しの公式ドキュメントは [Clojure - java_interop](http://clojure.org/java_interop) にあります。

クラスの new は 以下のどちらで書いても良いようです。

```clojure
(new ClassName args*)
(ClassName. args*)
```

インスタンスのメソッド呼び出しはこう書きます。

```clojure
(.methodName object args*)
```

早速試してみました。Java 側が不必要にややこしい設計なのは気にしないことにします。

```java:/src/Fib.java
public class Fib {
    private int num;

    public Fib(int num) {
        this.num = num;
    }

    private static int calcWithNum(int num) {

        return (num == 1) ? 1
            : (num == 2) ? 1
            : calcWithNum(num - 1) + calcWithNum(num - 2);
    }

    public int calc() {
        return calcWithNum(this.num);
    }
}
```

```clojure:/src/Hello.clj
(print (.calc (Fib. 7)))

```

```:実行結果
13
Process finished with exit code 0
```

……こっこれは楽しそうな予感。Qiita のシンタックスハイライトに clojure があるのもうれしいですね！

嬉しがって Java から Clojure の呼び出しをしようとすると、ドキュメントにある clojure.java.api.Clojure というクラスが見つかりません・・

# Clojure のバージョンを 1.6.0 にする

La clojure プラグインは現在だと Clojure 1.5.1 が設定されているようです。

Java から Clojure を呼び出す方法が Clojure 1.6.0 でだいぶ簡単になったので、ライブラリを 1.5.1 から 1.6.0 に更新します。

* Project Structure ... -> Libraries で + を押して From Maven.. を選択
* clojure と入力してしばらく待つとリストがでてくるので、一番下の org:clojure:clojure:1.6.0 を選択
* 1.5.1 を削除

これで clojure.java.api.* が使えるようになりました。

# Java から Clojure を呼び出す

ついでに Clojure のネームスペースも使ってみようとしたところ、理解不足のため少々苦戦しました。

まず .clj ファイルの配置ルール。

例えば mylib.myfunc というネームスペースを使う場合、

* ネームスペースの最後の部分(``myfunc``)をファイル名にする（小文字でよい）
* それ以前の部分(``mylib/``)をディレクトリ構造にする

という流儀のようです。

これを Java から呼び出す場合、ソースコード(.clj)はクラスパスが通っているディレクトリに配置しておく必要があります。

IntelliJ の場合は以下から設定できます

- File -> Project Structure... で設定画面を開く
- 左側の縦のメニューから Project Settings/Modules を選び、右側の Sources タブを選択
- clojure ソースコードファイルを配置したディレクトリのルートになるディレクトリ(今回は ``<project_home>/src/clojure``) を選んで右クリックして「Resource」

そんなこんなで作成した Clojure のソースは以下です

```clojure:/src/clojure/mylib/myfunc.clj
(ns mylib.myfuc)

(defn fib
  "Calculate Fibonacci number for given x"
  [x]
  (cond
    (= x 0) 0
    (= x 1) 1
    (= x 2) 1
    :else (+ (fib (- x 2)) (fib (- x 1)))))

```

Java からこれを呼び出すためのコードは以下のようになります。

``IFn myvar = Clojure.var("namespace", "variable");`` で Clojure側で定義した関数や値を取得して、``myvar.invoke(...);`` で実行する形が基本です。

```java:/src/java/com/example/Hello.java
package com.example;

import clojure.lang.IFn;
import clojure.java.api.Clojure;

public class Hello {
    public static void main(String[] args) {
        Clojure.var("clojure.core", "require").invoke(Clojure.read("mylib.myfunc"));
        IFn fib = Clojure.var("mylib.myfuc", "fib");
        System.out.println(fib.invoke(7));
    }
}
```

``clojure.core`` 以外のネームスペースを使う場合は、いったん require を invoke しなければならないところに注意。

何度も呼び出す場合はキャッシュ化するのもよさそうです。

参考:[Adding Awesomeness to your Legacy Java projects - falkoriemenschneider.de](http://www.falkoriemenschneider.de/a__2014-03-22__Add-Awesomeness-to-your-Legacy-Java.html)


```text:実行結果
13

```

起動には5-10秒くらい待たされます