Kotlin 「開いたレンジ」の詳細を探る
※本記事はQiitaに投稿していた記事のexportです(元投稿日: 2018/8/13)
Kotlin イン・アクションの第7章「7.3.2 inの規約」の中で 開いたレンジ(open range) という言葉が出てきます。(P.242 1行目)
開いたレンジとは、終端を含まないレンジを指します。例えば、10..20という記法を使い、通常の(閉じた)レンジを作る場合、このレンジには20も含む10から20の全ての数値が含まれます。10 until 20という開いたレンジには、10から19までが含まれますが、20は含まれません。
聞いたことがない表現なので、Kotlin用語なのか質問したり調べた結果をまとめます。
Kotlin イン・アクション読書会で質問
こちらのtweetで告知されている読書会で質問してみました。
お知らせ:今日の14時過ぎからKotlin in Actionの読書会をオンライン開催します。第2部 第7章「演算子オーバーロードとその他の変換の規約」について講師に翻訳者の @satorufujiwara をお招きし、YouTube Liveで @ikkou さんが配信協力です。最初なので試験放送ですのでなんかあったらまじごめんね。
— mhidaka@技術書典 応援祭 (@mhidaka) 2018年7月19日
回答は「開いた・閉じたという表現は数学的な用語」とのこと。 またハッシュタグ #merstudy を追ったところ 「開区間/閉区間に対応してるのかな」というtweetが出てきて、調べてみたらその通りでした。集合知有り難し。
開区間・閉区間
定義
金沢工業大学さんのサイト から定義を引用します。
区間とは ,数直線上のある区切りの間の数(実数)の集合のことである.区切りの数を含むか含まないかで区間の呼び方が異なり,開区間,閉区間,半開区間がある. 区切りを含む場合を閉区間という. 区切りを含まない場合を開区間という 片方の区切りを含み,他方の区切りを含まない場合を半開区間という
自分の感覚では「開いた」の方が範囲が広そうなのに狭いのが不思議だったのですが、図を見ると区切りの丸が○の方が開いている(空いている、含まない)で、●の方が閉じている(埋まっている、含む)ので、納得しました。もう間違えない。
untilで開いてるのは片方だけ
jetbrains社のKotlinブログに What’s new in Standard Library M13 and M14 という記事があり、ここにもレンジの説明がありました。 そこでは right-open ranges とあり、「右側(数字の大きい方)が開いている」と明言してありました。
Constructing open ranges There was a common request to introduce right-open ranges in Kotlin. We have examined use-cases and found that most of them are involving integer ranges. In case of integers an opened at the end range can be represented with a closed range, whose end value is one less than the corresponding open range’s end. To create such ranges you can use newly introduced until function. It returns closed range with values up to the specified end but not including it, so that: 0 until 20 == 0..19
wikipediaのintervalのページ#Classification_of_intervals)にある、「Left-closed, right-open」という表現とも一致しています。納得。
Kotlin 用語なのか?
「レンジ」がKotlinのクラス名なので、ある意味Kotlin用語かもしれません。 数学の「区間」は英語にすると上記wikipediaの通り「interval」です。 他のプログラミング言語でも「レンジ」クラスやメソッドが出てきたら「開いたレンジ」と言えるものはありそうです。
他の言語でのright-open ranges
最後の値を含む・含まない両方を表現できる言語はこの辺りがあるようです。他にもありそうですがこれぐらいで。
Java8
IntStream.rangeClosed(10, 15) // 10,11,12,13,14,15 IntStream.range(10, 15) // 10,11,12,13,14
Ruby
10..15 # 10,11,12,13,14,15 10...15 # 10,11,12,13,14
Swift
10...15 // 10,11,12,13,14,15 10..<15 // 10,11,12,13,14
Scala
10 to 15 // 10,11,12,13,14,15 10 until 15 // 10,11,12,13,14
まとめ
参考ドキュメント
n..mやrange(n, m)など範囲型やrangeと呼ばれるものでmは含まれるかどうかを調べてみた https://qiita.com/aimof/items/f25af524b3866c5706aa