List系関数の対応表 (Kotlin ⇔ Haskell)

*このページはまだ完成していません。がんばって加筆します。*



## まえがき

普段はKotlinでリスト操作系関数を使ってゴリゴリ書いているのですが、ふとしたときHaskellで似たようなことをやろうとすると「どうやって書くんだっけ？」となり、「PHPみたいに関数検索が簡単にできたらなぁ……」となるので、自分で作っています。

目標はこちらの記事で挙げられているKotlin関数を網羅することです。
[Kotlin の Collection まとめ ～List編～](https://qiita.com/kiririnyo/items/aee905225902d096f7c0)



## リスト生成

| Description        | Kotlin                                                       | Haskell                            |
| ------------------ | ------------------------------------------------------------ | ---------------------------------- |
| 基本               | listOf(1, 2, 3)<br />listOfNull(1, 2, 3, null)               | [1, 2, 3]                          |
| レンジ(昇順)       | (1 .. 10).toList()<br />(1 ... 11).toList()                  | [1 .. 10]                          |
| レンジ(降順)       | (10 downTo 1).toList()                                       | [10 .. 1]                          |
| 等差レンジ         | (1 .. 101 step 10).toList()<br />(101 downTo 1 step 10).toList() | [1, 11 .. 101]<br />[101, 91 .. 1] |
| 無限等差リスト     | -                                                            | [1, 3 ..]                          |
| 無限循環リスト     | -                                                            | cycle [1, 2, 3]                    |
| 無限長の単一リスト | -                                                            | repeat N<br />[N ..]               |
| 固定長の単一リスト | List(n) { N }                                                | replicate n N                      |

## 基本操作

| Description        | Kotlin               | Haskell               |
| ------------------ | -------------------- | --------------------- |
| リストの結合       | .plus(LIST)          | (++) [1, 2, 3] [4, 5] |
| 先頭へ要素追加     | .add(0, N)           | N : [1, 2, 3]         |
| 要素数の取得       | .size()              | length [1, 2, 3]      |
| 指定要素の取得     | .get(N - 1), [N - 1] | [1, 2, 3] !! N        |
| 先頭の取得         | .first()             | head [1, 2, 3]        |
| 末尾の取得         | .last()              | last [1, 2, 3]        |
| 先頭から指定長取得 | .take(N)             | take N [1, 2, 3]      |
| 末尾から指定長取得 | .takeLast(N)         | drop N [1, 2, 3]      |
| 先頭以外の取得     | .drop(1)             | init [1, 2, 3]        |
| 末尾以外の取得     | .dropLast(1)         | tail [1, 2, 3]        |
| 空リスト判定       | .isEmpty()           | null [1, 2, 3]        |
| 要素を含むか       | .contains(N)         | elem N [1, 2, 3]      |
| 逆順               | .reversed()          | reverse [1, 2, 3]     |
| 重複の削除         | .distinct()          | nub [1, 2, 3]         |

## 高階関数系：基本

| Description                            | Kotlin                           | Haskell                                                      |
| -------------------------------------- | -------------------------------- | ------------------------------------------------------------ |
| *通例：〜以外を返す*                   | .xxxNot { Fn }                   | xxx (not . (Fn)) [1, 2, 3]                                   |
| *通例：末尾から〜する*                 | .xxxLast { Fn }                  | xxx Fn $ reverse [1, 2, 3]                                   |
| 合致要素のみ残す                       | .filter { Fn }                   | filter Fn [1, 2, 3]                                          |
| 最初の合致要素を取得                   | .find { Fn }                     | find Fn [1, 2, 3]                                            |
| 各要素に適用                           | .map { Fn }<br />.forEach { Fn } | map Fn [1, 2, 3]                                             |
| 左から畳み込み<br />(初期値を使用)     | .fold(N) { Fn }                  | (正格) foldl' Fn N [1, 2, 3]<br />(遅延) foldl Fn N [1, 2, 3] |
| 右から畳み込み<br />(初期値を使用)     | .foldRight(N) { Fn }             | (正格) foldr' Fn N [1, 2, 3]<br />(遅延) foldr Fn N [1, 2, 3] |
| 左から畳み込み<br />(初期値は先頭要素) | .reduce { Fn }                   | (正格) foldl1' Fn [1, 2, 3]<br />(遅延) foldl1 Fn [1, 2, 3]  |
| 右から畳み込み<br />(初期値は末尾要素) | .reduceRight { Fn }              | (正格) foldr1' Fn [1, 2, 3]<br />(遅延) foldr1 Fn [1, 2, 3]  |

## 高階関数系：タプル・多重リスト系

現在整理中



## あとがき

Haskell→Scala→Kotlinという親子関係があるため、全体を通して似ている部分が多いです。例えば引数の順序はほぼすべて同じですし、関数名もおおむね一致しています。

しかしKotlinのほうが後発ゆえに関数名に規則性ができて洗練されている上に、関数のオーバーロードができるおかげで似たような関数名で迷うことがないため、関連付けによる記憶が非常にしやすくなっています。文字数をなるべく少なくしたいHaskellとは違い、KotlinではJavaの風習に倣って省略記法をあまり用いないことも覚えやすい一因でしょうか。

一方でHaskellは無限リストの作成や(ここには書いていない)リスト内包表記などがある分リスト生成に優れている、という印象……というよりはKotlinが`[]`を用いたリスト宣言ができない時点で他言語に少し劣ると思っています。もっと言えば全体的にスマートな記述ができないのが欠点といったところでしょうか。
ただそこら辺はCollection実装周りで諸事情があるので仕方ないような気もしますし、言ってしまえば「何をもって読みやすさ/管理しやすさを評価するか」がKotlinとHaskellとでは大きく異なるため比較するのは野暮なのかもしれません。

なお「Scala使えばいいじゃん」というのは宗教的理由で禁止です。ご了承を。