KisaragiEffective.github.io

Yeet.

View on GitHub

可変長タプル on Kotlin?

https://qiita.com/yyu/items/4941417ec555ea5ab590 に触発されて一部をKotlinで実装してみようと思い立った。 ただし、元記事と違いがあり:

基本的な定義

sealed class Tuple

class Body<out A, out B : Tuple>(val head: A, val rest: B) : Tuple()

object Tail : Tuple()

サイズ

fun Tuple.size() = size(0)

tailrec fun Tuple.size(acc: Int): Int {
  return when (this) {
    is Body<*, *> -> this.rest.size(acc + 1)
    Tail -> acc
  }
}

取り出し

// auto
operator fun <E> Tuple.get(index: Int): E {
  return get(0, index) as E
}

tailrec fun Tuple.get(acc: Int, index: Int): Any? {
  if (acc == index) {
    when (this) {
      is Body<*, *> -> return head
      Tail -> throw IndexOutOfBoundsException()
    }
  } else {
    when (this) {
      is Body<*, *> -> return this.rest.get(acc + 1, index)
      Tail -> throw IndexOutOfBoundsException()
    }
  }
}

分解宣言

// usage:
// val (a, b, c, d) = tuple
// it's syntax-sugar for:
// val a = tuple[0]
// val b = tuple[1]
// val c = tuple[2]
// val d = tuple[3]
fun <E1> Body<E1, Tuple>.component1() = this[0] as E1
fun <E1, E2> Body<E1, Body<E2, Tuple>>.component2() = this[1] as E2
fun <E1, E2, E3> Body<E1, Body<E2, Body<E3, Tuple>>>.component2() = this[2] as E3
fun <E1, E2, E3, E4> Body<E1, Body<E2, Body<E3, Body<E4, Tuple>>>>.component2() = this[3] as E4
fun <E1, E2, E3, E4, E5> Body<E1, Body<E2, Body<E3, Body<E4, Body<E1, Tuple>>>>>.component2() = this[4] as E5
// あぁ!関数が加速度的に増えてゆく・・・