Slide 1

Slide 1 text

関数型プログラミング

Slide 2

Slide 2 text

はじめに この分野で技術的にきちんと 検証していると古い英語論文 ひっくり返す必要が出てくる ので、事実の記述は割とおお ざっぱです。ご了承ください。

Slide 3

Slide 3 text

関数型プログラミングとは 関数型プログラミ ングとはなにか? 決まった定 義はない。

Slide 4

Slide 4 text

LISP LISP •最初の関数型言語 •1958年~

Slide 5

Slide 5 text

当時の3大言語 • 数値演算プログラムを効率的に書くために作られた FORTRAN • 業務処理を英語が読み書きできれば記述できるように作 られた COBOL • 自動機械にラムダ演算を行わせる研究を机上でやってい たが、たまたま研究成果をマシン語で実装してみたら動 いた LISP

Slide 6

Slide 6 text

得意としていたこと FORTRAN 科学計算 科学者が 記述 COBOL 業務処理 コーダが 記述 LISP AI アルゴリズ ムを工夫

Slide 7

Slide 7 text

関数型プログラミングのメリット 保守性や可読性のための様々な工夫が山 盛りでなされている 数学的なシンプルさをプログラム上で利用で きる

Slide 8

Slide 8 text

高階関数 関数型プログラミングの特徴の一つ ラムダ演算から出てきた記法 関数が第一級オブジェクトとして扱える

Slide 9

Slide 9 text

高階関数 char* data[] = {"Apple", "Microsoft", "Google", "Oracle", "Dell"}; char deleted = 'O'; resultNum = 0; for(i = 0; i < dataNum; i++){ /* 頭文字がbad以外のもののみを結果として抽出 */ if(data[i][0] != deleted){ result[resultNum++] = data[i]; } } /*文字列数でソート*/ for(i = 0; i < resultNum; i++){ for(j = i + 1; j < resultNum; j++){ if(strlen(result[j]) < strlen(result[i])){ tmp = result[i]; result[i] = result[j]; result[j] = tmp; } } } C var data = "Apple" :: "Microsoft" :: "Google" :: "Oracle" :: "Dell" :: Nil var deleted = "O" var result = data filter(!_.startsWith(deleted)) sortWith(_.size < _.size) Scala

Slide 10

Slide 10 text

高階関数 data = %w(Apple Microsoft Google Dell Oracle) deleted = "O" result = data .find_all{|s| !s.start_with? deleted} .sort{|l, r| l.size <=> r.size} Ruby var data = new[] { "Apple", "Microsoft", "Google", "Oracle", "Dell" }; var deleted = "O"; var result = from s in data where !s.StartsWith(deleted) orderby s.Length select s; var data = new[] { "Apple", "Microsoft", "Google", "Oracle", "Dell" }; var deleted = "O"; var result = data .Where(s => !s.StartsWith(deleted)) .OrderBy(s => s.Length); Dim data = New String() {"Apple", "Microsoft", "Google", "Oracle", "Dell"} Dim deleted = "O“ Dim result = From s In data Where Not s.StartsWith(deleted) Order By s.Length Select s C# C# (メソッド構文) Visual Basic $data = array('Apple', 'Microsoft', 'Google', 'Oracle', 'Dell'); $deleted = 'O'; $result = array_filter($data, function($s) use ($deleted){return substr($s, 0, 1) != $deleted;}); usort($result, function($l, $r){return strlen($l) - strlen($r);}); PHP List data = Arrays.asList("Apple", "Microsoft", "Google", "Oracle", "Dell"); String deleted = "O"; Stream result = data.stream() .filter(s -> !s.startsWith(deleted)) .sorted((l, r)->l.length() - r.length()); Java data = ['Apple', 'Microsoft', 'Google', 'Dell', 'Oracle'] deleted = 'O' result = [x for x in sorted(data, key=len) if not x.startswith(deleted)] Python @data = qw/Apple Microsoft Google Dell Oracle/; $deleted = "O"; @result = sort {length $a <=> length $b} (grep /^[^$deleted].*/, @data); Perl

Slide 11

Slide 11 text

高階関数 (def data ["Apple" "Microsoft" "Google" "Oracle" "Dell"]) (def delete ¥O) (sort #(< (count %)(count %2)) (filter #(not (= (first %) delete)) data)) Clojure data = ['Apple', 'Microsoft', 'Google', 'Oracle', 'Dell'] deleted = 'O' result = (s for s in data when s.charAt(0) != deleted) result.sort (l, r) -> l.length - r.length CoffeeScript var data = ['Apple', 'Microsoft', 'Google', 'Oracle', 'Dell']; var deleted = 'O'; var result = data.filter((s) => !s.startsWith(deleted); result.sort((l, r) => l.length - r.length); Dart let data = ["Apple"; "Microsoft"; "Google"; "Oracle"; "Dell"] let deleted = "O" let result = data |> List.filter(fun s -> not(s.StartsWith(deleted))) |> List.sortBy(fun s -> s.Length) F# |data deleted result| data ← #('Apple' 'Microsoft' 'Google' 'Dell' 'Oracle'). deleted ← 'O'. result ← data select:[:s | (s beginsWith: deleted) not]. result ← result sortBy:[:l :r | (l size) < (r size)]. Smalltalk var data = "Apple" :: "Microsoft" :: "Google" :: "Oracle" :: "Dell" :: Nil var deleted = "O" var result = data filter(!_.startsWith(deleted)) sortWith(_.size < _.size) Scala JavaScript let data = ['Apple', 'Microsoft', 'Google', 'Oracle', 'Dell']; let deleted = 'O'; let result = data.filter(s=>s.charAt(0) != deleted); result.sort((l, r)=>l.length - r.length); var data = ['Apple', 'Microsoft', 'Google', 'Oracle', 'Dell'] var deleted = 'O' var result = data.filter(s=>s.charAt(0) != deleted) result.sort((l, r)=>l.length - r.length) TypeScript

Slide 12

Slide 12 text

高階関数 let data = ["Apple", "Microsoft", "Google", "Oracle", "Dell"] let deleted = "O“ var result = data.filter({ !$0.hasPrefix(deleted) }) result.sort({count($0) < count($1)}) Swift let data = ["Apple", "Microsoft", "Google", "Oracle", "Dell"]; let deleted = "O"; let mut result : Vec<&&str> = data.iter().filter(|s| !s.starts_with(deleted)).collect(); result.sort_by(|l, r|l.chars().count().cmp(&r.chars().count())); Rust auto data = ["Apple", "Microsoft", "Google", "Oracle", "Dell"]; const deleted = 'O'; auto result = data.filter!(s => s[0] != deleted).array; result.sort!((l, r)=>l.length < r.length); D val data = array("Apple", "Microsoft", "Google", "Oracle", "Dell") val deleted = 'O' val result = data.filter{it[0] != deleted} sortBy{it.length} Kotlin NSArray *data = [NSArray arrayWithObjects:@"Apple", @"Microsoft", @"Google", @"Oracle", @"Dell", nil]; NSString *deleted = @"O"; NSIndexSet *filteredIndexes = [data indexesOfObjectsPassingTest: ^(id obj, NSUInteger idx, BOOL *stop){return (BOOL)![obj hasPrefix:deleted];}]; NSArray *result = [[data objectsAtIndexes:filteredIndexes] sortedArrayUsingComparator: ^(id l,id r){ NSNumber *lLength = [NSNumber numberWithUnsignedInteger:[l length]]; NSNumber *rLength = [NSNumber numberWithUnsignedInteger:[r length]]; return [lLength compare:rLength]; }]; Objective-C $data = 'Apple', 'Microsoft', Google', 'Oracle', 'Dell' $deleted = 'O' $result = $data | ?{$_ -notlike "$deleted*"} | Sort-Object Length Powershell vector data = { "Apple", "Microsoft", "Google", "Oracle", "Dell" }; auto deleted = 'O'; auto newEnd = remove_if(data.begin(), data.end(), [&](auto s) { return s[0] == deleted; }); data.erase(newEnd, data.end()); sort(data.begin(), data.end(), [](auto l, auto r) { return l.size() < r.size(); }); C++

Slide 13

Slide 13 text

高階関数 今では普通です ね

Slide 14

Slide 14 text

最近普通のプログラミング Ifやforでプログラムを書く時代はもう終わりました 簡単な繰り返し処理や分岐なら別ですが データ生成なんかは高階関数を利用したコレク ション処理ライブラリ使いましょう

Slide 15

Slide 15 text

IF文やFOR文を使わない const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] .filter(i => i % 3 == 0) .map(i => i * i)

Slide 16

Slide 16 text

いっそLINQ.JSで const data = Enumerable.range(-10, 20) .where(i => i % 3 == 0) .orderByDescending(i => i % 5) .select(i => i * i) .toArray(); SQLで書けるとは大体書けるよう設計されています

Slide 17

Slide 17 text

余談 関数型プログラミングのメリットは大げさに言われる傾向がある気が する 昔は可読性などを追及しているのが関数型言語だけだったので、 関数型言語のみが未来の言語だというのは正しかったんですが。 言い続けている間に、他の言語が追い付いてきているので。

Slide 18

Slide 18 text

宣言的記法 for文やif文は書かない どう計算するかではなく、結果がどうなるかを記述する 時間経過に沿ってコードを負う必要がなくなる 数学的関数と同じように扱える

Slide 19

Slide 19 text

宣言的記法 あくまでコードの見た目の話。 •実際の実行は必ず順序をもって行 われるので

Slide 20

Slide 20 text

宣言的記法 let sorted = data.sortBy(x => {return x.length;}); let sorted = data.sortBy(x => x.length); より宣言型に

Slide 21

Slide 21 text

変数の再代入はしない 変数の再代入をしない ローカル変数も、インスタンス変数も これを守れば宣言的記法

Slide 22

Slide 22 text

副作用を持たない 変数の変更が撲滅できない場合 せめて変更の影響は関数の中に収める 外から変更の影響が見えない 副作用を持たない関数

Slide 23

Slide 23 text

副作用を持たない 副作用を持たないオブジェクト指向とか可能? JavaやC#のString型はやっています インスタンス変数は不変。 結果は必ずインスタンスを作り直して返す。

Slide 24

Slide 24 text

関数型プログラミングとオブジェクト指向 オブジェクト指 向 抽象データ型 段階的な抽象 化 構造化プログ ラミング

Slide 25

Slide 25 text

関数型プログラミングとオブジェクト指向 関数型プログ ラミング 抽象データ型 段階的な抽象 化 構造化プログ ラミング

Slide 26

Slide 26 text

純粋にオブジェクト指向の機能 レシーバ オブジェクト指向の三大要素 • カプセル化 • 継承 • ポリモーフィズム

Slide 27

Slide 27 text

ドット記法 メソッドのドットの前に書くレシーバは、論理的 には引数の一種です 関数プログラミングで引数と言った時は、 レシーバを含めると考えましょう a.method(b, c); method(a, b, c); 同じ意味

Slide 28

Slide 28 text

オブジェクト指向の三要素 • 情報を隠蔽し、結合度を下げる カプセル化 • 大量のい関数(メソッド)をわかりやすく整 理し、共通化する 継承 • 継承で整理したメソッドを整理された状態 で呼び出すことによりわかりやく利用する ポリモーフィズム 関数型プログラミングと競合するようなことはやってない