関数型プログラミング
- ちゃんと勉強したい
- 関数型プログラミングは宣言型プログラミングという、より大きなパラダイムの一部
- 計算のモデルの違い
- 命令型
- 計算とは命令を実行すること
- チューリング機械
- 関数型
- 計算とは関数を呼び出して値を得ること
- アロンゾ・チャーチ
- 論理型
- 計算とは証明を得ること
- 命令型
使いたい言語
Immutability
- 不変性
- 副作用がない
- 変数の値を変えない
-
0から99までの数値を出力するプログラム
-
命令型の場合、変数iに値を保持し、状態を変更し、その結果を出力する
-
for(int i = 0; i < 100; i++) { console.log(i); } -
関数型の場合、再帰を使い、iの状態は変更しない
-
function f(i) { if(i > 99) { return; } else { console.log(i); return f(i+1); } } f(0);
-
Referential Transparency
- 参照透過性
- 関数を値と置き換えても結果が変わらない
- Date.now()は評価の度に異なる値が返ってくるので参照透過でない
- purityとも近い概念
- 同じ入力に対して同じ出力が返ってくる
- 副作用がない
- ファイル書き出しやエラー処理は副作用
Higher Order Functions
- 高階関数
- 関数を引数に取る関数
-
リストの中身を2乗したい場合
-
命令型
-
function square(nums) { let squared = []; for(let i = 0; i < nums.length; i++) { squared.push(nums[i] * nums[i]); } return squared; } -
関数型
-
function square(nums) { return nums.map(function(n) { return n * n; }); }
-
Lazy Evaluation
- 遅延評価
- 必要になるまで評価されない
- Haskellは遅延評価がデフォルト
- 対義語はEager Evaluation(先行評価)
- 関数が呼ばれる度にif文が評価される
-
function myIf(condition, thenAction, elseAction) { if(condition) { thenAction(); } else { elseAction(); } }
Lambda calculus
- ラムダ計算
- 関数型プログラミングの基礎
- JavaScriptのアロー関数はラムダ計算の直接的な翻訳
JavaScriptでの使い所
1回だけ実行する
- ボタンを1回だけ押せるようにしたい場合
- グローバル変数でフラグを使う
- 実行されたらイベントハンドラをnullにする
- などが考えられるが、使い回せなかったり状態の管理が複雑になったりする
-
const once = (fn) => { let done = false; return (...args) => { if (!done) { done = true; return fn(...args); } } } const f = message => console.log(message); const doOnce = once(f); doOnce("hi!"); doOnce("hi!");
数学の知識
- Set Theory(集合論)
- domain(定義域)とrange(値域)
- 集合と写像
- Category Theory(圏論)