個人事業主になったので真面目にアウトプットしてみるブログ

フリーで顧客の会社に潜り込んでAndroidアプリつくって、とりあえず食っていけるようにアウトプットを増やしていくブログです。

Kotlinのletってなんか変

(let [[x y z] [1 2 3]] 
         (+ x y z))
;; 6

これはClojureのlet

(let ((x 1) (y 2) (z 3))
         (+ x y z))
;; 6

これはその元になったLispのlet

これはどちらも、局所変数と言われるものだ。(OCamlやSwiftにもletがあるが、そちらの話は省く。)

そもそもletというのは、数学でいうとあらかじめ「xは〇〇」とするというときに let x is XX という使い方をされる経緯があるために作られたものらしい。

今回の問題はKotlinのletなのだけど。正直存在の理解に苦しむ。

Triple(1, 2, 3).let { (x, y, z) -> x + y + z }
// 6

そしてletはその定義のせいで、高階関数のmapと同様にみられてしまうきらいがあるようだ。 なので僕はletは使いたくなるが、本質的にLisp系言語で使われるようなものとは違うので、あまり好きではない。

もう言語として互換性を考えるとこれらの定義を覆そうとするのは無駄骨だろう。 しかも新たに独自に定義してしまおうとも思えない。

ただ違う世界線が存在したならこういう定義であればいいな?

public inline fun <T, R> let(receiver: T, block: (T) -> R): R {
    return block(receiver)
}
public inline fun <T, R> T.map(block: (T) -> R): R {
    return block(this)
}

つまりこうなる

1.map{ "$it" } // "1"
let(Triple(1,2,3)) { (x, y, z) -> x + y + z } // 6

こうしてやっておけばletの使い方に誰も困らなかったんじゃないか?かえって混乱を生まなくて済んだんじゃないか?という気がしてくる。

ちなみにこの定義を二つ同時に作ると、letを亡きものにしつつ、mapという新しいもので上書きするからなのか?コンパイルできなくなるようだ。


普段はこういうものはTwitterでしか書かないんだけど何度も同じことを考えるのでいい加減ブログに書いておきたくなったし、そう時間かからないので書いておいた。