オブジェクト指向と関数型プログラミング：関数型プログラミング編



オブジェクト指向プログラミングObject Oriented Programming (以下OOP), 関数型プログラミングFunctional Programming (FP)のコンセプトを紹介します．どっちがいいって訳はなく、どっちも超頭いい先人たちが思いついたアイデアなので知っていて損は無いし、何なら両方使っちゃえばって感じです．

考え方の紹介なのでコードは（あんまり）無いです．長くなってしまったので今回は関数型プログラミングを主に扱います．どうせオブジェクト指向はいろいろ記事出てるし．







## なんでこんなこと考えるのさ？



OOP、FPはプログラムを整理する手法、つまり考え方の１つです．

そのためこれら以外の方法でプログラムを書いても実行できますが、何も計画なしでコードを書き続けるとそのうち管理が大変になったり、修正に大変な労力を必要とするクソコードになってしまうかもしれません（いわゆるスパゲッティコードと呼ばれる状態ですね）．





![img](https://upload.wikimedia.org/wikipedia/commons/4/40/Spagetti_code_structural_graphic.GIF)

> **スパゲッティコード**とは、コンピュータプログラムの状態を表す俗語の一つで、命令の実行順が複雑に入り組んでいたり、遠く離れた関連性の薄そうな[コード](http://e-words.jp/w/コード.html)間で共通の[変数](http://e-words.jp/w/変数.html)が使われるなど、処理の流れや構造が把握しにくい見通しの悪い状態になっているプログラムのこと。
>
> （IT用語辞典より）



では 効率の良くコードを整理するにはどうすれば良いのでしょうか？

この問題はプログラムを使う開発者みんなが直面しています．だからこそプログラムが1940年代に誕生してから（たぶん）、あなたよりも遥かに頭の良い先人たちが、数多くの方法を試してきました[1]．



> [1] History of programming languages https://en.wikipedia.org/wiki/History_of_programming_languages (Wikipedia)



ある方法は読みやすさを優先したり、ある方法は柔軟に変更しやすいように、またある方法は拡張性を重視しました．そんな数多の手法の内現在特に多くの人に支持され人気のある手法が、そうです、今回紹介するOOPとFPです．





今ならこの記事を読んでOOP、FPを学ぶことで先人つよつよプログラマーの英知をなんとタダでパクれます．といってもこの記事を書いている僕自身はクソ雑魚ナメクジなので、ナメクジに咀嚼されていないオリジナルで崇高なアイデアを知りたい人は[1]のWiki記事やオライリー様の素晴らしい書籍などを参考にするといいでしょう．



---



先にも書いていますがOOP、FPは考え方です．コンセプトです．なので使うプログラミング言語に限定されることではありません．（もちろんある言語によってはOOPの方が書きやすかったり、ほかの方法は書きにくかったりしますし、`JavaScript`のようにOOP、FP両方使いやすい言語もありますが）



また、この界隈には某キノコタケノコ戦争並みに過激な思考を持ち、自分の支持する手法以外を全否定するおじさん（もしくはおばさん）もいるでしょうが、残念ながらきのこの山のように完璧に絶対的に他方のゴミよりも優れている手法は今のところありません（僕は知りません）．手が汚れてキーボードを破壊する短小の里なんて選ぶわけないじゃん．



両方の手法を紹介しますが１つを溺愛するのではなく、峰不二子がルパンに愛想を振りつつ悪党とも手を組むように複数の候補を都合よく使えるだけ使いましょう．





## 関数型プログラミング：FP

前置きが長くなりましたが、それではFPについて紹介します．



FPのイメージは小さな部品（Function, 関数）をたくさん用意して必要に応じて、クソガキやクソじゃないガキや、良い年した大人が*大人の○○*っていいよねとか自分に言い聞かせて遊んでいる積み木のように組み合わせて使う感じです．



![image-20201028220729901.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472945/cd6f1250-8aa1-5688-dcae-87cf66dfb71d.png)

> Photo by [Nathan Dumlao](https://unsplash.com/@nate_dumlao?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/lego?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)

> まあ、LEGOみたいなもんです <  積み木じゃないじゃん





ポイントは部品となる各関数をできるだけシンプルにすることです．LEGOでも色々な小さな部品をたくさん持っていると好き勝手に想像次第で色々作れますよね．逆にデス・スターを作れるキットではデススターを作るにはいい感じな特別に加工された部品はありますが、それをデススター以外に使うのは向いていないって思いませんでした？思いましたよね．そう、向いてないんです．



<img src="https://images.unsplash.com/photo-1587654780291-39c9404d746b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1000&q=80" alt="yellow red blue and green lego blocks" style="zoom:50%;" />

> Photo by [Xavi Cabrera](https://unsplash.com/@xavi_cabrera?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/lego?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)

> FPで目指すのはこんなLEGOのように小さくて使いやすい関数をたくさん用意することです（だと僕は思います）





### 関数型プログラミングで使いたい関数のポイント

じゃあ具体的にどんな関数がいいのさ？



#### ポイント１：1 task

各関数は１つのことだけやります（そうなるまで分解しましょう）．

スマホと運転は同時にはできません．無理すると某不思議医者みたいに事故にあって指の震えが止まらなくなって得意な手術ができなくなって同僚に冷たく当たった挙句髭ぼうぼうに生やした状態でつよつよハゲ女に幻覚みせられて最終的には宇宙ゴリラとタイマンする羽目になりますからね．



<img src="https://i.chzbgr.com/full/8131140352/hADC06DA0/might-as-well-screw-up-better" alt="Multitasking screw up idiots funny - 8131140352" style="zoom:100%;" />

> Might as Well Screw Up Better by [Very Demotivational](https://memebase.cheezburger.com/verydemotivational)





#### ポイント２：再現性（同じinput -> 同じoutput）

文字通りです．同じinputを与えれば何千回実行しても同じoutput, 戻り値になるようにしましょう．





#### ポイント３：NO副作用

ここでいう副作用、side effectとは関数の外の環境のことです．関数を実行するたびに、例えばグローバル変数が変わってしまうのは避けましょう．


![image-20201031200509680.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472945/83471e7c-fac2-9128-1209-640691e52cd6.png)



これを避けるには

- 操作したいデータのコピーをつくる 
- -> いろいろ
- -> 計算結果を戻り値として返す、



とするといいでしょう．



でもコピーを作るとメモリー消費しちゃう！助けてドラえもん～って思いませんでした？



大丈夫のび太君．こんなこともあろうかと用意しておいたものがあるんだ．

それは．．．



コウゾウキョウユウー `Structural Sharing` 

![structural-sharing.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472945/973bca67-a82f-d89f-c834-958d43db93ba.png)




オリジナルと違う部分だけメモリーに新しくつくって、同じ部分はメモリーを共有すればいいってこと．頭いいね．



あとは関数内で変数を作るといいらしいよ．`closure`ってやつだね．そうすると変数たちがそれぞれの関数でしか使えないから意図しない変更を防げるってわけ．やっぱ先人は頭いいね．





#### ポイント４：引数と出力の数は少なく（simple is the best）

これも文字通りです．特に後で説明するFP最大の利点、複数の関数を組み合わせる`compose`を行う際に重要になってきます．引数`argument`は１個、多くても２、３個に抑えましょう．



`argument`を減らすには`currying`というテクニックが使えます．

![Image for post](https://miro.medium.com/max/938/1*it9EJUjHQU9fGLzSD0ip_A.png)

> Getting started with Functional Programming by [**Anwesha Chatterjee**](https://medium.com/@anweshachatterjee?source=post_page-----609575254919--------------------------------): https://medium.com/@anweshachatterjee/getting-started-with-fp-609575254919

> `currying`について説明しています．





##### `currying`とは

関数を分解して引数を１つずつ取るように分解することです．



イメージとしてはこんな感じ

`f(a, b, c, ...) => f(a)(b)(c)...`



習うより慣れよ、というわけでコードを見てみましょう．



例えば引数を２つ受け取ってその合計を返す`add(a, b)`という関数やその掛け算を返す`multi(a, b)`は

```javascript
const add = (a, b) => a + b;
const multi = (a, b) => a * b;
```



引数を一つずつ取るように下のように分解できます．シンプルですね

```javascript
const curriedAdd = (a) => (b) => a + b;
const curriedMulti = (a) => (b) => a * b;

console.log(curriedAdd(2)(3)) // 5
console.log(curriedMulti(2)(3)) // 6
```



`currying`の利点として途中で止めることで色々な派生形の関数を作れることがあります．

例えば`curriedAdd`を途中で止めることで`add5()`や`add10()` を作れます．このようにして作成した関数`add5`などは、プログラムの中で他の関数と同じように使えるわけです．便利ですね．



```javascript
const add5 = curriedAdd(5)
const multi2 = curriedMulti(2)

console.log(add5(5)) // 10
console.log(multi2(3)) // 6
```



#### ポイント５：他の関数と組み合わせ（compose）

では、先ほど作った`add5()`, `multi2()` を組み合わせて引数を２倍してその後５を足した値を返す関数`multi2AndAdd5()`を作ってみましょう．



そのためには指定した関数を組み合わせて新しい関数として返す関数が必要ですね（関数って単語使いすぎ）．要は関数`f`と関数`g`を組み合わせた内容を行う新しい関数`composedFunction`を返す仕組みを作りたいってことです．



イメージとしては

```
composedFunction = compose(f, g)
```

みたいなことがしたいわけです．



`JavaScript`には`compose`を行うライブラリがあります．`Ramda`とかですね．

https://github.com/ramda/ramda

![image-20201031185040937.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472945/b55ae9f2-13d2-5492-e953-35d654de04d7.png)


２つだけ組み合わせるならそこまで難しくないので今回は自分で作ってしまいましょう．

というわけで２つの関数を引数として、それらを順に行いその結果を戻り値として返す関数を作成する関数`compose(f, g)`は



```javascript
const compose = (f, g) => (a) => f(g(a))
```

と書けます．そんなに難しくないですね．`g(a)`で関数`g`の処理を行った結果を関数`f`が受け取って`f`の処理を行うってことです．



今回は`f`も`g`も１つだけ引数をとる関数なので簡単に書けましたが、もし複数とる場合はどうするんですかね（知らないけど）？

両方とも例えば２つの引数を取る場合は`a`の部分を`a, b`とすればいけそうですけど、`a`と`b`の順番とか、どうやって保障するんですかね（知らないけど）？

それに`f`, `g`の受け取る引数の数が違ったりしたらもっと面倒ですよね．



ということで`compose`したいなら引数は極力少なく、戻り値も１つだけにしたいってことです．

そうなるまで関数を分解するテクニックの１つが`currying`ですね．



ちょっと脱線しましたが`compose()`を使って、先ほど作った`add5()`, `multi2()` を組み合わせて引数を２倍してその後５を足した値を返す関数`multi2AndAdd5()`を作ってみましょう．

```javascript
const multi2AndAdd5 = compose(add5, multi2)

console.log(multi2AndAdd5(5)) // 5 * 2 + 5 = 15
```



こうして例を見てみると`compose`もそんな難しくないですよね．こうやって`compose`で作った関数も他の普通の関数みたいにプログラムの他のところで繰り返し使えるわけです．便利







### まとめ



今回はクソみたいな例でしたのでもう少しマシなものを使っておさらいしましょう．

例えば機械学習の前処理で画像を編集する時などに、前処理全てを１つの関数にまとめるのではなく、画像を引数として処理結果の画像を返す関数をいくつも用意して組み合わせる書き方にすることでそれぞれの関数が短く済んで管理しやすくなりそうですよね．



シンプルで１つのことをNO副作用でやる関数を用意して

- applyFilter(img)
- removeNoise(img)
- compress(img)
- ...



これらを組み合わせた関数を作る

```javascript
applyPreprocess = compose(applyFilter, removenoise, compress, ...)
              
applyPreprocess(img)
```



気に食わない処理過程があれば`compose`から除けばいいし、簡単に他の処理も追加したり順番変えたり融通利きそうですよね．



この記事で伝えたかったというか、僕の考えは、`compose`のコンセプト、もとい関数型プログラミングを知っていることで、小さい関数を沢山用意して必要に応じてそれらを組み合わせて使う方法もあるよな、って頭の引き出しに使えるアイデアが持てるようになるとイイよねってことです．



次オブジェクト指向について書こうかなって思ったけど二番煎じどころじゃないし．いらないかな．．．