Python で関数型プログラミング（っぽいもの）に入門する

## はじめに

最近、 [exercism.io](https://exercism.io/) を始めたのですが、Pythonでちょっと面白い問題に遭遇しました。Pythonで関数型プログラミングをやってみろという課題です。この課題を通じて関数型プログラミングに入門するための基本的な考え方を解説を試みます。なお、筆者は、Pythonも関数型プログラミングもずぶの素人です。

なお、ここでは、Python 3.7.0 を動作確認に使ってます。

## 課題

（全部、そのまま掲載するのはどうかと思うので、代表して１つだけ記載します。）

Python の既存の関数を使わずにリストの基本操作の１つ `append`関数を実装してください。

```python
append([], []) # => []
append([], [1, 2, 3, 4]) # => [1, 2, 3, 4]
append([1, 2], [2, 3, 4, 5]) # => [1, 2, 2, 3, 4, 5]
```

## 関数型プログラミング（っぽいもの）の基本的な考え方

関数型プログラミングでは、リスト（配列）を扱うのは、基本中の基本です。リストの先頭の値を求める、リストの先頭を除いた残りを求める、リストの先頭に１つ値を追加して新たなリストを作る、などです。こういった基本的な操作を組み合わせて、リストに対する関数を実装していくことになります。
大体、関数型プログラミングを勉強すると最初の方で、基本的な操作が登場してきます。（Scheme だと car, cdr, cons などですね。）

## Pythonでリストの先頭を取り出す

Pythonのリスト `list` の先頭を取り出すやり方はいろいろあるでしょうが、ここでは、以下のやり方を使います。

```python
head, *tail = list
```

ここで、head には、listの先頭が入ります。 

```python
>>> list = [1, 2, 3]
>>> head, *tail = list
>>> head
1
>>>
```

`list[0]` とやってもいいのでしょうが、関数型プログラミング言語 Elixir を少しだけ触ったことがある筆者はこちらの方が好みです。

ちなみに、Elixir だとこんな感じです。

```elixir
[head|tail] = list
```

あと、Pythonでは、リストが空のときは、ValueErrorになるので注意しましょう。

```python
>>> list = []
>>> head, *tail = list
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: not enough values to unpack (expected at least 1, got 0)
```

## Python でリストの先頭を除いた残りを求める

もう既に登場してますね。 

```python
head, *tail = list
```

`tail` が先頭を除いた残りになります。

```python
>>> list = [1, 2, 3]
>>> head, *tail = list
>>> tail
[2, 3]
```

## Python でリストの先頭に１つ値を追加して新たなリストを作る

head が１つの値、tailがリストだとすると、tail に head を先頭につけたリストは以下のようにするとできます。

```python
list = [head, *tail]
```

実際の例はこんな感じです。

```python
>>> head = 1
>>> tail = [2, 3]
>>> list = [head, *tail]
>>> list
[1, 2, 3]
```

## Python でリストの末尾に１つ値を追加して新たなリストを作る

Python では、同じ要領で末尾にひとつ要素を追加して新たなリストを作ることもできます。headがリストで、tailが１つの要素だとすると

```python
list = [*head, tail]
```

とできます。実際の例はこんな感じ。

```python
>>> head = [1, 2]
>>> tail = 3
>>> list = [*head, tail]
>>> list
[1, 2, 3]
```

## append の実装

これまでの操作を組み合わせるとこんな感じで append を実装することができます。

```python
def append(xs, ys):
    while ys != []:
        head, *ys = ys
        xs = [*xs, head]
    return xs
```

以下のように再帰呼出しにする方が関数型プログラミングっぽいのですが、リストの要素の数が多くなると、RecursionError になるので、避けた方が良いでしょう。

```python
def append(xs, ys):
    if ys == []:
        return xs
    head, *ys = ys
    return append([*xs, head], ys)
```

## まとめ

Pythonで関数型プログラミング（っぽいもの）に入門してみました。同様にして、map関数、filter関数、foldl関数、foldr関数なども実装することができます。
なお、私が実装したコードに対して、mentor さんからのコメントが、まだついてません。ですので、これが正解かどうかはわかりません :sweat_smile: 

## おまけ

試してないですが、同じようなことは、Ruby でもできるはずです（社名が社名なので、やっぱりRubyを無理矢理にでも絡めておかないと :smile: )

```ruby
$ irb
irb(main):001:0> list = [1,2,3]
=> [1, 2, 3]
irb(main):002:0> head, *tail = list
=> [1, 2, 3]
irb(main):003:0> head
=> 1
irb(main):004:0> tail
=> [2, 3]
irb(main):005:0> [head, *tail]
=> [1, 2, 3]
irb(main):006:0> [*tail, head]
=> [2, 3, 1]
irb(main):007:0>
```

## 追記　（2018-09-13)

その後、メンターさんから `well done` とコメントもらいました。ただ、アドバイスとして、 

```python
while ys != []:
```

は

```python
while ys:
```

と書いた方が速いと言われました。 `[]` が false になるんですね。

```python
>>> a = []
>>> bool(a)
False
>>> a = [1]
>>> bool(a)
True
```

Ruby は（確か Elixir も） nil と false だけ false なので、その癖が出てしまいました :sweat_smile: