Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

16

Share

Download to read offline

【Topotal輪読会】JavaScript で学ぶ関数型プログラミング 1 章

Download to read offline

1/22 に行われた輪読会の資料です。

Related Books

Free with a 30 day trial from Scribd

See all

【Topotal輪読会】JavaScript で学ぶ関数型プログラミング 1 章

  1. 1. JavaScript で学ぶ 関数型プログラミング 1章 Topotal 輪読会 髙村成道(@nari_ex) 2015/1/22
  2. 2. 1.1 JavaScript に関する事実
  3. 3. 関数型プログラミング言語をサポート 引数として関数を渡すことができる [1,2,3].forEach(alert); // アラート"1"がポップアップ // アラート"2"がポップアップ // アラート"3"がポップアップ → 引数に渡した関数に配列の要素を順番に渡して実行する
  4. 4. JavaScript の驚異的な柔軟性 JavaScript の三銃士 → apply, arguments, call
  5. 5. apply メソッド • すべての関数において実装されているメソッド • 引数 1 つ目: this オブジェクト • 引数 2 つ目: 配列 fun.apply(thisArg, array) • 与えられた配列を関数の引数として渡して実行することがで きる
  6. 6. apply メソッドを用いた例 function splat(fun) { return function(array) { // null を指定すると暗黙的にグローバルオブジェクトに変換される return fun.apply(null, array); }; } var addArrayElements = splat(function(x, y) { return x + y }); addArrayElements([1, 2]); //! 3 返り値として関数を返す関数 → 関数型プログラミングの入り口!
  7. 7. arguments 変数 • すべての関数内で arguments ローカル変数にアクセス可能 • 関数呼び出し時に引数として与えられた値を保持 function func() { for (var i = 0, l = arguments.length; i < l; i++) { alert(arguments[i]); } }; func(1,2,3) //! 1 //! 2 //! 3
  8. 8. call メソッド apply と同様に、引数に与えられた値を関数に渡して実行 第2引数に、配列ではなく個別の引数を受け取る fun.call(thisArg, [, arg1 [, arg2, ...]]);
  9. 9. call メソッドと arguments 変数を用いた例 • 任意の引数を渡すことが可能 function unsplat(fun) { return function() { return fun.call(null, _.toArray(arguments)); }; } var joinElements = unsplat(function(array) { return array.join(' ') }); joinElements(1, 2); //! "1 2" joinElements('-', '$', '/', '!', ':'); //! "- $ / ! :"
  10. 10. 1.1.1 JavaScript の制限
  11. 11. 欠点 • 奇妙な仕様 • 安全性に欠けている • グローバルスコープに依存している • 命令型プログラミングをサポート • 競合するライブラリの山 • 多くのモジュールが実装されたがそれぞれに互換性はない
  12. 12. 命令型プログラミングと 宣言型プログラミング 例: 「レジの会計で合計値を計算する」
  13. 13. 補足: 命令型プログラミング 1. 品物がカゴに残っていれば 2. へ、空であれば 5. へ進む。 2. 品物を取り出す。 3. 価格を合計値に足す。 4. 1. へ戻る。 5. 合計値を表示する。 → 順番が異なる場合に破綻する
  14. 14. 補足: 宣言型プログラミング 1. 合計値とは、カゴの中の品物をあるルールで処理した結果 • ルールA. 品物が0個の場合、合計値は0である。 • ルールB. 品物が1個以上の場合、合計値は、カゴの中の品 物1つの価格と、残りの品物の合計値を足した値である。 → 順序関係なし、安全かつ簡潔
  15. 15. 欠点はあるがしかし... • 一定の規則を遵守することで一筋の光を見出すことができる • 安全性が確保される • コードベースのサイズに比例してスケーラビリティが増す • シンプルでわかりやすく、テストしやすいコードになる → 本書では、それらを関数型プログラミングによって導く
  16. 16. 1.2 関数型プログラミングを始めるた めに
  17. 17. 関数型プログラミングとは 値を抽象の単位に変換する関数を使用して行うプログラミング であり、それらを使ってソフトウェアシステムを構築すること
  18. 18. 1.2.1 なぜ関数型プログラミングが必 要なのか
  19. 19. オブジェクト指向型のシステム • オブジェクトをたくさん組み合わせることでゴールを目指す • 例: ボタンを押して情報を出すアプリケーション • ShowButton → HiddenPanel → InfoPanel... オブジェクト同士が互いに関連している → オブジェクトの変更や追加をしようとしたときに、システム の状態を考慮する必要がある
  20. 20. 関数型のシステム • 関数を組み合わせて(合成して)値を変換していく • 例: markdown → toHTML → postProcess → modifyDOM • postProcessは、visit,post,addId,genId 関数で構成 機能追加時は新しい関数の動作を理解すればよい。 データ変換を繰り返し行うことでシステムを構築するのが関数 型プログラミング。
  21. 21. 1.2.2 抽象単位としての関数
  22. 22. 抽象化 抽象化の方法として、実装詳細を隠 することが挙げられる ここでは、エラーや警告を報告するプログラムを考える
  23. 23. function parseAge(age) { if (!_.isString(age)) throw new Error('引数は文字列である必要があります'); var a; console.log("age を数値に変換しようとしています"); a = parseInt(age, 10); if (_.isNaN(a)) { console.log(["age を数値に変換できませんでした : ", age].join('')); a = 0; } return a; }
  24. 24. parseAge("42"); // age を数値に変換しようとしています //! 42 parseAge(42); // Error: 引数は文字列である必要があります parseAge("frob"); // age を数値に変換しようとしています // age を数値に変換できませんでした : frob //! 0
  25. 25. サンプルコードの問題点 • エラー内容を変えたくなった時にそれぞれを出力する行を変 更する必要がある • 情報、警告、エラーを使い分けたい場合も同様
  26. 26. 関数に抽象化 functon fail(thing) { throw new Error(thing); } function warn(thing) { console.log(["警告 : ", thing].join('')); } function note(thing) { console.log(["情報 : ", thing].join('')); }
  27. 27. サンプルコード 改 function parseAge(age) { if (!_.isString(age)) fail('引数は文字列である必要があります'); ☆ var a; note("age を数値に変換しようとしています"); ☆ a = parseInt(age, 10); if (_.isNaN(a)) { warn(["age を数値に変換できませんでした : ", age].join('')); ☆ a = 0; } return a; }
  28. 28. 1.2.3 カプセル化と隠
  29. 29. オブジェクト指向言語の場合 データの要素のパッケージングにオブジェクトの境界を使用 メソッド経由でデータを操作することでデータをパッケージ化
  30. 30. 関数型プログラミングの場合 クロージャを使ってデータをカプセル化して隠 する
  31. 31. 1.2.4 動作単位としての関数
  32. 32. コンパレータ(comparator) • 2つの値を引数に取る • 1つ目の引数が2つ目よりも小さい場合: 負の値を返す • 1つ目の引数が2つ目よりも大きい場合: 正の値を返す • 1つ目の引数が2つ目よりも等しい場合: 0を返す
  33. 33. 例: sort() 辞書順なので数字の大小に関係なくソートされる [2, 3, -6, 0, -108, 42].sort(); //! [-108, -6, 0, 2, 3, 42] [0, -1, -2].sort(); //! [-1, -2, 0] [2, -3, -1, -6, 0, -108, 42, 10].sort(); //! [-1, -108, -6, 0, 10, 2, 3, 42]
  34. 34. comparator 関数を用いた場合 function compareLessThanOrEqual(x,y) { if (x < y) return -1; if (x > y) return 1; return 0; } [2, -3, -1, -6, 0, -108, 42, 10].sort(compareLessThanOrEqual); //! [-108, -6, -3, -2, -1, 0, 10, 42] if (compareLessThanOrEqual(1,1)) cosolelog("同じか小さい"); // なにも表示されない
  35. 35. プレディケート(predicate) 常に真偽値を返す関数 function lessOrEqual(x, y) { return x<=y; } if (lessOrEqual(1,1)) consolelog("同じか小さい"); // 同じか小さい [2, -3, -1, -6, 0, -108, 42, 10].sort(lessOrEqual); //! [42, 10, 0, -1, -2, -3, -6, -108] ← 逆順になってる
  36. 36. 高階関数によるマッピング 関数を引数にとり、新しい関数を生成して返す関数 function comparator(pred) { return function(x, y) { if (truthy(pred(x, y))) return -1; else if (truthy(pred(y, x))) return 1; else return 0; }; [100,1,0,10,-1,-2,-1].sort(comparator(lessOrEqual)); //! [-2,-1,-1,0,1,10,100]
  37. 37. 1.2.5 抽象としてのデータ • 関数は、ある世界からある世界への橋渡しを行う • 例: 文字列→数値, 文字列→配列, 配列→配列の組... データを抽象的にとらえ、異なるデータへ変換することに意識 を集中させる
  38. 38. 1.2.6 関数型テイストの JavaScript
  39. 39. 有用な関数その1: existy() • 存在しないことを判定する function existy(x) { return x != null }; existy(null); existy(undefined); existy({}.notHere); existy((function(){}()); //! false existy(0) existy(false) //! true
  40. 40. 有用な関数その2: truthy() 与えられた値が true とみなされるかどうかを判定する function truthy(x) { return (x !== false) && existy(x) }; truthy(false); truthy(undefined); //! false truthy(0); truthy(''); //! true
  41. 41. existy, truthy の応用 true なら実行、それ以外なら undefined を返す function doWhen(cond, action) { if (truthy(cond)) return action(); else return undefined; }
  42. 42. Array#map 配列のそれぞれの要素に対して引数に与えた関数を実行し、 それぞれの実行結果を格納した配列を返す [null, undefined, 1, 2, false].map(existy); //! [false, false, ture, true, true] [null, undefined, 1, 2, false].map(truthy); //! [false, false, ture, true, false]
  43. 43. つづき 先ほどのコードでは、以下のようなことが行われている • 関数を装った存在の抽象の定義 (existy) • 既存の関数を使って構築された真値の抽象の定義 (truthy) • これらの関数を他の関数のパラメータに渡すことによる新た な動作の実現 (truthy, existy と map の組み合わせ) これこそが関数型プログラミング!!!
  44. 44. 1.2.7 実行速度について
  45. 45. 関数型プログラミングで記述しても遅くならない よ • 流行りの V8 エンジンはランタイム最適化してくれるぜ • オプティマイザは賢いから気張ってコーディングしないでok • 関数型プログラミングすると必ず速度低下することはない • 関数型プログラミングはコーディングの時間は短縮する
  46. 46. 1.3 Underscore について • なんで使ったの • いちいち map とか実装してる暇はない • map の実装ではなく概念が説明したいんじゃ! • Underscore は基本的なライブラリがきちんと ってる • 車輪の再発明しても益少なかろうよ → Topotal 1系...
  47. 47. 1.4 まとめ • 入門的なトピックを扱った • JavaScript アプリケーションを構築する一つの方法が「関数 型プログラミング」 • 抽象を導き出して関数として構築する • すでに存在する関数を使って、より複雑な抽象を構築する • すでに存在する関数を別の関数に渡すことによって、さら に複雑な抽象を構築する
  • SugiyamaYuichi

    Mar. 10, 2020
  • minorusano77

    Dec. 24, 2015
  • junichiwatanuki

    Oct. 9, 2015
  • maruuun

    Jul. 28, 2015
  • chikuwas

    May. 20, 2015
  • shunsuketadokoro

    May. 17, 2015
  • ssuser1b7f9a

    Feb. 14, 2015
  • syuichitsuji

    Feb. 11, 2015
  • hidekism

    Jan. 22, 2015
  • xxshimizuxx

    Jan. 22, 2015
  • jessiepiccolotti

    Jan. 22, 2015
  • chihirourabe

    Jan. 22, 2015
  • yasufumitaniguchi1

    Jan. 22, 2015
  • toshiyukiihara3958

    Jan. 22, 2015
  • LastArrow1

    Jan. 21, 2015
  • tetsuoyutani

    Jan. 21, 2015

1/22 に行われた輪読会の資料です。

Views

Total views

3,738

On Slideshare

0

From embeds

0

Number of embeds

231

Actions

Downloads

18

Shares

0

Comments

0

Likes

16

×