8
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

凍った唐揚げ弁当なるオブジェクト

Posted at

関数型プログラミングはまず考え方から理解しよう
ともぐい、ともぐいをする。 (つまり、からあげのつまみ方とは。)
唐揚げつまんでみた
唐揚げもうひとつだけ

をみていて、なんでオブジェクト指向捨てちゃうの?と_何かが間違っている_思考に捕らわれました。

ということで、凍った唐揚げ弁当なるオブジェクトを考えることにしました。ECMAScript5以前のJavaScriptだとクラスを書くのが面倒現代風1っぽくないので、ECMAScript2015で書きます。

karaage.es6
"use strict";
class Bento {
  constructor(karaageNumber) {
    this._karaageNumber = karaageNumber
  }
  get karaageNumber() { return this._karaageNumber; }
  karaagePick(number = 1) {
    return Object.freeze(new Bento(this.karaageNumber - 1));
  }
  toString() {
    return `唐揚げ: ${this.karaageNumber}`
  }
}

class BentoSet {
  constructor(list) {
    this._list = Object.freeze(list.slice(0));
  }
  get list() { return this._list; }
  indexOfMaxKaraageBento() {
    return this.list.reduce((accs, bento, idx) =>
      accs[1] < bento.karaageNumber ? [idx, bento.karaageNumber] : accs
    , [0, 0])[0];
  }
  karaagePick(number = 1) {
    if (number <= 0) {
      return this;
    } else {
      const max_index = this.indexOfMaxKaraageBento();
      return Object.freeze(new BentoSet(this.list.map(
        (bento, idx) => idx === max_index ? bento.karaagePick() : bento
      ))).karaagePick(number - 1);
    }
  }
  toString() {
    return this.list.join(", ");
  }
}

const bentoSet = Object.freeze(new BentoSet(
  [
    Object.freeze(new Bento(10)),
    Object.freeze(new Bento(8)),
    Object.freeze(new Bento(6))
  ]
));
console.log(bentoSet.toString());
console.log(bentoSet.karaagePick(1).toString());
console.log(bentoSet.karaagePick(2).toString());
console.log(bentoSet.karaagePick(3).toString());
console.log(bentoSet.karaagePick(4).toString());
console.log(bentoSet.karaagePick(5).toString());
console.log(bentoSet.karaagePick(6).toString());
console.log(bentoSet.karaagePick(7).toString());
λ node karaage.es6
唐揚げ: 10, 唐揚げ: 8, 唐揚げ: 6
唐揚げ: 9, 唐揚げ: 8, 唐揚げ: 6
唐揚げ: 8, 唐揚げ: 8, 唐揚げ: 6
唐揚げ: 7, 唐揚げ: 8, 唐揚げ: 6
唐揚げ: 7, 唐揚げ: 7, 唐揚げ: 6
唐揚げ: 6, 唐揚げ: 7, 唐揚げ: 6
唐揚げ: 6, 唐揚げ: 6, 唐揚げ: 6
唐揚げ: 5, 唐揚げ: 6, 唐揚げ: 6

お弁当とお弁当セットの二つのクラスを用意しました。唐揚げクラスも用意しようかと思いましたが、taste(味)ぐらいしかプロパティがなさそうなので断念しました。

さて、この弁当(とそのセット)ですが、Object.freeze()で凍らせています。凍った弁当から一つの弁当だけ取り出して、そこから唐揚げを摘まもうとしても不可能です。だって、凍り付いているのですから、箸で唐揚げ摘まもうとしても、弁当から離れません。

では、どうするかというと、ちょっとだけ違うクローンを作ることにしました。つまり、唐揚げ取り出しちゃった後の弁当を新たな弁当(とそのセット)として作ることにしたのです。それが、karaagePick()メソッドがやっていることです。

各クラスのメソッドは、副作用も無く、参照透明です2。レシーバも引数の一つとみなせば、純粋関数と解釈することができます。つまり、オブジェクト指向を捨てる必要なんて全くないんです。immutableのオブジェクトにすれば、関数型プログラミングと同じような発想とメリットで作ることができます。

あ、再帰部分って唐揚げが多いとスタックオーバーフローするような。食べ過ぎは良くないですし、あとで考えよう。

  1. もだーんってやつ。

  2. たぶん。

8
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?