サッカー日本代表のスタメンをKotlin DSLで記述する

# 概要
内部DSLを記述するのに向いている静的型付け言語、といえば`Scala`ですが、`Kotlin`もなかなかな柔軟性の高い言語機能を持っています。
書籍『[Kotlinイン・アクション](https://www.amazon.co.jp/Kotlin%E3%82%A4%E3%83%B3%E3%83%BB%E3%82%A2%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3-Dmitry-Jemerov/dp/4839961743/ref=tmm_pap_swatch_0?_encoding=UTF8&qid=&sr=)』の第11章に高度なテクニックが幾つか紹介されていますが、それらを使ったサンプルを作ってみました。
以下のようなDSLでフォーメーションとスターティングイレブンを記述します。

```kotlin
fun main(args: Array<String>) {
	val eleven = 
    	(formation / 4 - 5 - 1) {
        	FW += "大迫"
        	MF += "原口" / "南野" / "堂安" / "遠藤" / "柴崎"
        	DF += "長友" / "吉田" / "冨安" / "酒井"
        	GK += "権田"
    	} format """
			|         FW-1         
			|MF-1     MF-2     MF-3
			|      MF-4  MF-5      
			|DF-1  DF-2  DF-3  DF-4
			|         GK-1         
			|""".trimMargin()
    
    println(eleven)
}
```

出力は以下のようになります。（何ら実用性のないプログラムですが、サンプルなのでそこはご了承ください...）

```
         大迫         
原口     南野     堂安
      遠藤  柴崎      
長友  吉田  冨安  酒井
         権田         
```

以下、使っているテクニックを説明します。

# 演算子のオーバーロード

```kotlin
(formation / 4 - 5 - 1)
```

上記のように、文字列リテラルを使わずにフォーメーションを直にコードとして表現したかったのですが、普通に考えると `4 - 5 - 1` は`Int`同士の演算により `-2` と解釈されてしまいます。
それを回避するため、左側に演算子 `/` を置いています。上のコードを冗長に書くと、

```kotlin
( ( ( ( formation / 4 ) - 5 ) - 1 ) )
```

となります。
では、最も内側の括弧内は演算はいったい何なのでしょうか。
その正体は、`formation`という名前のオブジェクトに定義された`div`メソッドです。

```kotlin
object formation {
    infix operator fun div(df: Int) = FormationHelper1(df)
}
```

`Kotlin`における演算子のオーバーロードは規約ベースとなっています（特定の名前、シグネチャのメソッドを実装する）。
`/`をオーバーロードするには、`operator`修飾子を付けて`div`メソッドを実装します。また、中置演算を可能とするために`infix`も指定します。即ち、`formation./(4)` ではなく `formation / 4`という書き方を可能とします。

そして、`div`メソッドの戻り値は`FormationHelper1`というヘルパークラスのオブジェクトとなっています。

```kotlin
class FormationHelper1(private val df: Int) {
    infix operator fun minus(mf: Int) = FormationHelper2(df, mf)
}
```

このヘルパークラスでは、`minus`メソッドを実装することで、`-`演算をオーバーロードしています。
なので、`formation / 4 - 4` と書けます。
この`minus`メソッドの戻り値の`FormationHelper2`も同様の実装となっています。

```kotlin
class FormationHelper2(private val df: Int, private val mf: Int) {
    infix operator fun minus(fw: Int) = FormationHelper3(df, mf, fw)
}
```

# invoke、拡張関数型、レシーバ付きラムダ

その次のラムダ式は一体何なのでしょうか。

```kotlin
(formation / 4 - 5 - 1) { /* このラムダは？ */ }
```

まず、`(formation / 4 - 5 - 1)`の部分は`FormationHelper3`クラスのオブジェクトです（`FormationHelper2#minus`の戻り値）。演算子の優先順位の都合で、括弧で括っています。

その後ろのラムダ式が渡されるメソッドの実体は、以下の`invoke`メソッドです。

```kotlin
class FormationHelper3(private val numOfDf: Int,
                       private val numOfMf: Int,
                       private val numOfFw: Int) {
    // ..(略)..
    operator fun invoke(eleven: FormationHelper3.() -> Unit): FormationHelper3 {
        this.eleven()
        return this
    }
```

`operator`修飾子が付いていることから推測できるかと思いますが、これも規約ベースでのオーバーロードを行っています。
何をオーバーロードしているかというと、オブジェクトの関数的呼び出しです。
例えば、`Foo`クラスのオブジェクトを格納する変数`foo`があったとして、`Foo`が`Int`引数を一つ取る`invoke`メソッドを実装していたならば、`foo(1)`は`foo.invoke(1)`と等値となります。

上記の`FormationHelper3#invoke`の場合は、ラムダ式を一つ引数で受け取ります。
ただ、その引数の型の指定がちょっと見慣れない感じです。

```kotlin
FormationHelper3.() -> Unit
```

これは拡張関数型と呼ばれるものです。拡張関数型を使うと、レシーバ付きラムダというラムダ式を渡せるようになります。
レシーバ付きというのは、ラムダ式内でのメソッド呼び出しを受け取るオブジェクト（〜レシーバ）が紐づけられている、というイメージです。上記の場合、`FormationHelper3`型のオブジェクトをレシーバとし、引数なし、戻り値はUnit型であるラムダを受け取る拡張関数型、と読めます。

そして、実際にレシーバを紐づけて拡張関数型を実行するためには、以下のように`レシーバ.関数()`と記述します。この例ではたまたまレシーバ型が自分自身だったので`this`をレシーバとしていますが、別のオブジェクトでも構いません。

```kotlin
this.eleven()
```

そして、呼び出し側のレシーバ付きラムダは以下のようになっています。

```kotlin
    	(formation / 4 - 5 - 1) {
        	FW += "大迫"
        	MF += "原口" / "南野" / "堂安" / "遠藤" / "柴崎"
        	DF += "長友" / "吉田" / "冨安" / "酒井"
        	GK += "権田"
    	} 
```

このラムダ式内では、`this`がレシーバオブジェクトを参照し、各メソッド呼び出しやプロパティアクセスはレシーバに対するメッセージと解釈されます。
上記は`this`を省略していますが、明示的に書くと以下となります。

```kotlin
    	(formation / 4 - 5 - 1) {
        	this.FW += "大迫"
        	this.MF += "原口" / "南野" / "堂安" / "遠藤" / "柴崎"
        	this.DF += "長友" / "吉田" / "冨安" / "酒井"
        	this.GK += "権田"
    	} 
```

※なお、`FormationHelper3#invoke`メソッドの唯一の引数がラムダ式であるため、ラムダ式を外に括り出し、空になった `( )` は省略可能であることに注意してください。省略せずに書くと、以下のように冗長な感じになります。

```kotlin
    	(formation / 4 - 5 - 1) ({
        	this.FW += "大迫"
        	this.MF += "原口" / "南野" / "堂安" / "遠藤" / "柴崎"
        	this.DF += "長友" / "吉田" / "冨安" / "酒井"
        	this.GK += "権田"
    	})
```

# その他

```kotlin
MF += "原口" / "南野" / "堂安" / "遠藤" / "柴崎"
```

`+=`は`plusAssign`メソッド実装による演算子オーバーロードです。
右辺は、`String`を連結して`List<String>`を生成するように、拡張関数を定義しています（前述の`div`メソッド実装により`/`演算子をオーバーロード）。

```kotlin
infix operator fun String.div(other: String) = listOf(this, other)
infix operator fun List<String>.div(other: String) = this + other
```

その他細かい部分は、全ソースコードを添付するのでそちらを参照ください。

# 全ソースコード

動かしてみたい方は、[Try Kotlin](https://try.kotlinlang.org/#/Examples/Hello,%20world!/Simplest%20version/Simplest%20version.kt)に貼り付けて実行可能です。

```kotlin
fun main(args: Array<String>) {
	val eleven = 
    	(formation / 4 - 5 - 1) {
        	FW += "大迫"
        	MF += "原口" / "南野" / "堂安" / "遠藤" / "柴崎"
        	DF += "長友" / "吉田" / "冨安" / "酒井"
        	GK += "権田"
    	} format """
			|         FW-1         
			|MF-1     MF-2     MF-3
			|      MF-4  MF-5      
			|DF-1  DF-2  DF-3  DF-4
			|         GK-1         
			|""".trimMargin()
    
    println(eleven)
}

infix operator fun String.div(other: String) = listOf(this, other)
infix operator fun List<String>.div(other: String) = this + other

object formation {
    infix operator fun div(df: Int) = FormationHelper1(df)
}

class FormationHelper1(private val df: Int) {
    infix operator fun minus(mf: Int) = FormationHelper2(df, mf)
}

class FormationHelper2(private val df: Int, private val mf: Int) {
    infix operator fun minus(fw: Int) = FormationHelper3(df, mf, fw)
}

class FormationHelper3(private val numOfDf: Int,
                       private val numOfMf: Int,
                       private val numOfFw: Int) {
    private var keepers: List<String> = emptyList()
    private var defenders: List<String> = emptyList()
    private var midfielders: List<String> = emptyList()
    private var forwards: List<String> = emptyList()
    
    val FW: FormationHelper4
    	get() = FormationHelper4({xs -> forwards += xs}) 

    val MF: FormationHelper4
    	get() = FormationHelper4({xs -> midfielders += xs}) 

    val DF: FormationHelper4
    	get() = FormationHelper4({xs -> defenders += xs}) 

    val GK: FormationHelper4
    	get() = FormationHelper4({xs -> keepers += xs}) 
    
    operator fun invoke(eleven: FormationHelper3.() -> Unit): FormationHelper3 {
        this.eleven()
        return this
    }
    
    infix fun format(template: String): String {
        val regex = """(FW|MF|DF|GK)-([1-9])""".toRegex()
        var result = template
        regex.findAll(template)
        	.map { it.groupValues }
            .map { Pair(it[0], playerName(it[1], it[2].toInt())) }
        	.forEach { result = result.replace(it.first, it.second) }
        return result
    }
    
    private fun playerName(position: String, index: Int): String {
        val (list, max) = when (position) {
            "FW" -> Pair(forwards, numOfFw)
            "MF" -> Pair(midfielders, numOfMf)
            "DF" -> Pair(defenders, numOfDf)
            "GK" -> Pair(keepers, 1)
            else -> throw Exception("Invalid position ${position}")
        }
        if (index > max) {
            throw Exception("Too many players (${index}) in ${position} ")
        }
        return list[index - 1]
    }
}

class FormationHelper4(val callback: (List<String>) -> Unit) {
    infix operator fun plusAssign(player: String): Unit {
        callback(listOf(player))
    }
    infix operator fun plusAssign(players: List<String>): Unit {
        callback(players)
    }
}
```