無限大な夢のあと

テニスとアニメが大好きな厨二病SEのブログ

TypeScript+Underscore.jsで関数型プログラミング 第1回 ワードカウント問題

altJSであるTypeScriptと関数型でのプログラミングをサポートするUnderscore.jsを使い、関数型プログラミングについての理解を深めていくために、様々な問題を解いていく記事を定期的に記載していきたいと思います。

TypeScriptについて簡単に知りたい方はこちらを参照してください。
公式ページ
Welcome to TypeScript

参考になる記事
TypeScriptで学ぶJavaScript入門:第1回 TypeScriptの概要 (1/4) - @IT

Underscore.jsについて簡単に知りたい方はこちらを参照してください。
公式ページ
Underscore.js

参考になる記事
Underscore.jsの入り口:連載|gihyo.jp … 技術評論社


さて、第1回はワードカウント問題を解いていきたいと思います。
※ワードカウント問題などの例は下記のかとうじゅんいちさんの問題例から拝借させていただきました。
https://gist.github.com/j5ik2o/7210762

私は下記のように解いてみました。

ここからはコードの解説をしていきたいと思います。

  • 1行目

下記のコードでUnderscore.jsを読み込んでいます。

/// <reference path='typings/tsd.d.ts' />

TypeScriptでJavaScriptのライブラリを読み込む際にはHTMLでライブラリ自身を読み込む他に、別途方定義ファイルを読み込むことが必要となります。
型定義ファイルについて、詳しくはこちら。

TypeScriptの型定義ファイルを共有しよう! - Qiita
JavaScript - WebStorm で TypeScript を始めよう!《Advent Calendar 2014》 - Qiita
TypeScriptの型定義ファイル(d.ts)をTSDを用いて管理する。 | Developers.IO

  • 4行目

ここでは関数定義をしていますが、ここではTypeScriptのアロー関数式を使用しています。
ここのアロー関数式では{}を使わない記法を用いているため、関数定義ですがreturnを書く必要がありません。
値を返すことを前提としている関数型っぽい書き方を実現できるわけです。

var countFruitsFromLines = (list:string[]) =>

アロー関数式については下記を参考にしてください。
Playground - Welcome to TypeScript

  • 5行目

ここではUnderscore.jsを使用し、chainメソッドを使用しています。
Underscore.jsは_.メソッド名という形で使用します。
chainメソッドは、チェーン記法で連続処理を行うメソッドです。
チェーン内のそれぞれの関数はchainメソッドの引数で渡されたオブジェクトを処理した結果をラッパーオブジェクトに格納して、チェーン上の次のメソッドに渡します。
チェーン内のメソッドにはラッパーオブジェクトが渡され、メソッドの1つ目のパラメータは省略されます。

__.chain(list:string[])

chainメソッドについて、説明がわかりにくかった場合は下記の記事を参考にしてください。
第3回 underscore.jsの関数とユーティリティとChaining:Underscore.jsの入り口|gihyo.jp … 技術評論社

  • 7行目

ここでは、mapメソッドを使い、mapメソッドの引数にmapメソッドで実行されるメソッドの定義をアロー関数式で記述しています。
mapメソッドは、第1引数で渡される配列/オブジェクトのそれぞれの要素に対して、第2引数で定義された関数に渡して、実行した結果を配列で返します。
また、第1引数がオブジェクト型であっても戻り値は配列となります。
そして、今回はchainメソッドにより、mapメソッドに渡される第1引数は省略されています。
splitメソッドは、JavaScipt自体のメソッドで、引数で渡された文字列を区切り文字とし、レシーバの文字列を配列にして返すものです。

   .map((_list:string[]) => _list.split(' '))

mapメソッドについて、説明がわかりにくかった場合は下記の記事を参考にしてください。
第2回 Underscore.jsのコレクションと配列とオブジェクトの機能:Underscore.jsの入り口|gihyo.jp … 技術評論社

  • 9行目

ここでは、flattenメソッドを使い、ネストされている配列に関して、ネストを解いて平坦な新しい配列にして返しています。

   .flatten()

flattenメソッドについて、説明がわかりにくかった場合は下記の記事を参考にしてください。
第3回 underscore.jsの関数とユーティリティとChaining:Underscore.jsの入り口|gihyo.jp … 技術評論社

  • 11行目

ここでは、配列の要素をカウントし、それぞれの要素とその出現回数をキー値として格納したオブジェクトを返します。

   .countBy()

この関数の存在を知る前には下記のようなコードを記述していました。

   .reduce(function (counts, word) {
    counts[word] = (counts[word] || 0) + 1;
     return counts;
        },  {})

ちなみにreduce関数は第1引数に渡された配列/オブジェクトに関して、それぞれの要素を左から順番に第2引数で定義された関数に渡して実行し、その結果を結合することで単一の値まで煮詰めると言ったようなものです。
すごく簡単に言えば、再帰関数をこの関数で置き換えできるようなイメージです。
reduceの引数で定義している関数については、JavaScriptでよく使うイディオムを使用していますので初めて見た方は調べてみてください。

reduceメソッドについて、説明がわかりにくかった場合は下記の記事を参考にしてください。
第2回 Underscore.jsのコレクションと配列とオブジェクトの機能:Underscore.jsの入り口|gihyo.jp … 技術評論社

  • 13行目

このvalueメソッドは、chainメソッドの最後に記述するもので、ラッパーオブジェクトからchainメソッドの処理結果を抽出して返します。

  .value();

いかがでしたでしょうか。
関数型がまだあまりよくわかっていなくてコードを記述しているので、もっと良いやり方があるなど突っ込み等ありましたら、コメントしてくださると嬉しいです。

JavaScriptで学ぶ関数型プログラミング

JavaScriptで学ぶ関数型プログラミング

関数プログラミング 珠玉のアルゴリズムデザイン

関数プログラミング 珠玉のアルゴリズムデザイン

TypeScriptリファレンス Ver.1.0対応

TypeScriptリファレンス Ver.1.0対応

TypeScript実践プログラミング (Programmer's SELECTION)

TypeScript実践プログラミング (Programmer's SELECTION)