SlideShare a Scribd company logo
第3回 関数型入門
TypeScript & 関数型講座
今講座のコンセプト
関数型プログラミングを知らない人には
関数型プログラミングとはどういうものかを知ってもらう
関数型プログラミングを実践している人には
改めて、関数型プログラミングのメリットを整理する
関数型プログラミングとは
一言でいうならば
副作用を分離すること!
関数型プログラミング入門
プログラマが関数型プログラミングについて語るとき、めまいを起こしそうな数の“関数型”的な特徴に
ついて言及します。彼らは変更不能なデータや第一級関数や末尾呼び出し最適化について述べま
す。これらは関数型プログラミングを助ける言語の特徴です。そして彼らはマッピング、リデューシン
グ、パイプライン化、再帰法、カリー化、そして高階関数の使用法についての話に移ります。これらは
関数型のコードを書くのに使われるプログラミングテクニックです。それからさらに並列化や遅延評価、
決定性について言及するでしょう。これらは、関数型プログラムの長所です。
これらを全て忘れてください。関数型コードを特徴づけるのは、「副作用がない」という1
点です。関数型のコードは現在の関数の外部に存在するデータに頼りません。そして現在の関数の
外部に存在するデータを変更しません。
その他の“関数型”なものは、全てこの特性から派生しています。このことを学習の手がかりにしてくだ
さい。
参考資料
副作用とは?
諸説あるが、
- プログラムの状態を変化させ、それ以降で得られる結果に影響を与えること
- 変数の再代入
- 破壊的なメソッドの使用(これも内部的には変数への再代入をしている)
- 本来想定している作用とは別に発生する作用
- 例外 (約束事「関数シグネイチャー」を無視するため)
- 常に同じ値が返ってくるとは限らないこと
- DBへの読み書きなどの I/O実行(プログラム外部の状態に依存している)
- 乱数生成
参照透過性と純粋関数
参照透過性とは
- 同じ条件を与えれば必ず同じ結果が得られる性質
純粋関数とは
- 参照透過性を持つ
- 他のいかなる機能の結果にも影響を与えない(副作用を持たない)
- 上記のような性質を持つ関数
関数型プログラミングでは、純粋関数を組み合わせて処理のパイプラインを構築していく
ちなみに、参照透過性は関数のみならず、オブジェクトにも適用可能である。状態を持たない
オブジェクトは、ある意味で純粋関数とみなせる
副作用を局所化する
副作用を完全に無くすと何も出力ができなくなってしまうため、システムとしての意味がなく
なってしまう。そのため、副作用を完全になくすのではなく局所化し、影響範囲を極力少なくす
ることが関数型プログラミングの目的
pure
pure
pure
pure
pure
pure
pure
pure
pure
pure
pure
pure
impure
impure
impure
関数型プログラミングのメリット
プログラミングの分かりやすさ
- 再代入、破壊的なメソッドが使用しないことによるメリット
- 変数束縛時点で値が決まる。そのため、変数束縛以降の処理を細かく追わなくて
もよい
- 例外が発生しないことによるメリット
- メソッドシグネイチャー以外を考慮しなくてよい
- 補足:関数型プログラミングでは従来例外として表現していたものを、文脈として
表現する。文脈として表現されたものは、例外と異なり、型レベルで対処を強要す
るため、抜け漏れが無くなる
- 常に同じ値が帰ってくることによるメリット
- 結果を容易に推論できる
テストのしやすさ
- 入力が同じなら出力も同じ
副作用がある例
並列処理のしやすさ
- 状態を持っていると、スレッド間での取り回しが難しくなる
スレッド1 スレッド2
参照
参照
更新
別スレッドの処理に影
響される
スレッド1 スレッド2
参照値更新後の
オブジェクト生成
別スレッドの処理に影
響されない
参照
参照
状態なし状態あり
オブジェクト指向との関係
オブジェクト指向とは、データとその振る舞いをオブジェクトに閉じ込めるという考え方
諸説あると思うが、個人的には「データとその振る舞いをオブジェクトに閉じ込める」というのが
本質で、そのデータが可変かどうかは本質的なものではないと思うので、オブジェクト指向と
は両立すると思う
宣言型プログラミングとの関係
宣言型プログラミングは「対象の性質を宣言してプログラムを構成する」ことで特徴づけられ
る。すなわち、出力を得る方法ではなく、出力の性質・あるべき状態を記述することを「宣言
型」と称する。(wiki)
関数型プログラミングは宣言型プログラミングの一部だとされている(wiki)が、そんな事はな
いと思う(相性がいいのは認める)
関数型でも手続き的に書けるし、オブジェクト指向でも宣言的に書ける
val users: Seq[User] = userRepository.getAll()
// 出力する方法ではなく、出力の性質を記述している
val longNameUser = users.filter(user => 10 < user.name.length)
関数型言語はあくまで関数型プログラミングに有利な特徴を備えているだけ。重要なのは、副
作用を分離すること。
部分的に関数型的に書いていくだけでも、メリットは享受できる
関数型言語ではなくても
関数型プログラミングは可能
関数型のプログラミングテクニック
再代入禁止
関数型プログラミングでは、代入ではなく、束縛を行う(宣言時以降変更されない場合、
束縛という)
Scala では val、TypeScript では const、Java では final 修飾子で表現される
再帰関数
for や while でのループは再代入を伴うため、関数型プログラミングでは使用されない
(拡張 for 文は再代入が伴わないので、OK? )
その代わりに再帰関数で実現する(初めはとっつきにくいけど、慣れると for 文等より
理解しやすい)
def sum(init: Long, from: Int, to: Int): Long = {
if (from == to) init + to
else sum(init + from, from + 1, to)
}
sum(0, 1, 10) // 55
再帰関数の作り方
1. 必要な情報(関数シグネイチャー)を考える
2. 停止条件を考える
3. それ以外の場合の処理を考える
def sum(init: Long, from: Int, to: Int): Long = { // ①
if (from == to) init + to // ②
else sum(init + from, from + 1, to) // ③
}
末尾再帰最適化
再帰関数は普通に実装すると、スタックオーバーフローする可能性がある
これを回避するため、言語によっては末尾再帰最適化に対応しているものもある
末尾再帰最適化とは、再帰関数内で再帰呼び出しを行う部分が関数で最後に評価さ
れる場合、コンパイラが内部的に for や while に変換し、スタックオーバーフローしな
いようにしてくれるというもの
def sum(init: Long, from: Int, to: Int): Long = {
if (from == to) init + to
else sum(init + from, from + 1, to) // sum の呼び出しは最後に評価されるため、末尾再帰最適化対
象
}
末尾再帰最適化の対応状況
対応してない言語では再帰回数が多い再帰関数は使用しない方が良いかも
Scala 対応
Java 非対応
JavaScript 非対応?
高階関数
再帰関数を使わなくちゃいけないのはわかったけど、毎回書くの面倒だよね
そこで、map, foldLeft(reduce)ですよ
for や while を使いたい場面には共通点がある
- あるリストに対して、その全ての値を変換する場合
- リストの全ての要素を走査して、単一の値を算出する場合
こうした振る舞いを共通化したのが、map や foldLeft
map
リストの map は、その全ての値を変換する処理を共通化したもの
リストに格納されている値を受け取り、単一の値を返す関数を引数に取る
(1 to 10).map(x => x * 2) // Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
foldLeft
foldLeft(JavaScript とかだと reduce)は、リストの全ての要素を走査して、単一の値を
算出する処理を共通化したもの
初期値と、そこまでの累積値及びリストに格納されている値を受け取り、単一の値を返
す関数を引数に取る
※ちなみに Java の reduce は並行処理を許可する関係で、モノイド則を満たす型でし
か使えないようなので注意
(1 to 10).foldLeft(0)((acc, x) => acc + x) // 55
高階関数
map や foldMap のように、関数を引数に取る関数、もしくは関数を返す関数を高階関
数と呼ぶ
カリー化
カリー化とは、複数の引数をとる関数を、引数が「もとの関数の最初の引数」で戻り値
が「もとの関数の残りの引数を取り結果を返す関数」であるような関数にすること(ある
いはその関数のこと)。(wiki)
def add(x: Int, y: Int): Int = {
x + y
}
// カリー化した場合
def add(x: Int)(y: Int): Int = {
x + y
}
function add(x: number): (y: number) => number { // TypeScript では
return y => x + y
}
部分適用
部分適用とは、カリー化された関数に一部のみ引数を適用すること。
これにより、処理の冗長性を排除できる
def add(x: Int, y: Int): Int = {
x + y
}
// 第一引数に必ず 1 が渡される場合
val test1 = add(1, 1)
val test2 = add(1, 2)
val test3 = add(1, 3)
val test4 = add(1, 4)
def add(x: Int)(y: Int): Int = {
x + y
}
val add1 = add(1) _ // add1: Int => Int = <function>
val test1 = add1(1)
val test2 = add1(2)
val test3 = add1(3)
val test4 = add1(4)
まとめ
関数型プログラミングとは副作用を分離するプログラミングスタイルである
関数型プログラミングには以下のメリットがある
- わかりやすい
- テストしやすい
- 並列処理しやすい
関数型プログラミングは関数型言語でなくてもできる
関数型プログラミングテクニック
- 変数束縛
- 再帰関数と高階関数
- カリー化と部分適用

More Related Content

What's hot

不遇の標準ライブラリ - valarray
不遇の標準ライブラリ - valarray不遇の標準ライブラリ - valarray
不遇の標準ライブラリ - valarray
Ryosuke839
 
プログラムを高速化する話
プログラムを高速化する話プログラムを高速化する話
プログラムを高速化する話
京大 マイコンクラブ
 
C++でできる!OS自作入門
C++でできる!OS自作入門C++でできる!OS自作入門
C++でできる!OS自作入門
uchan_nos
 
メタプログラミングって何だろう
メタプログラミングって何だろうメタプログラミングって何だろう
メタプログラミングって何だろうKota Mizushima
 
リクルート式 自然言語処理技術の適応事例紹介
リクルート式 自然言語処理技術の適応事例紹介リクルート式 自然言語処理技術の適応事例紹介
リクルート式 自然言語処理技術の適応事例紹介
Recruit Technologies
 
Portacle : Common Lispのオールインワン開発環境
Portacle : Common Lispのオールインワン開発環境Portacle : Common Lispのオールインワン開発環境
Portacle : Common Lispのオールインワン開発環境
Satoshi imai
 
「いい検索」を考える
「いい検索」を考える「いい検索」を考える
「いい検索」を考える
Shuryo Uchida
 
Pythonによる黒魔術入門
Pythonによる黒魔術入門Pythonによる黒魔術入門
Pythonによる黒魔術入門
大樹 小倉
 
20160526 依存関係逆転の原則
20160526 依存関係逆転の原則20160526 依存関係逆転の原則
20160526 依存関係逆転の原則
bonjin6770 Kurosawa
 
5分で解るセキュアコーディング
5分で解るセキュアコーディング5分で解るセキュアコーディング
5分で解るセキュアコーディング
Yasuo Ohgaki
 
リッチなドメインモデル 名前探し
リッチなドメインモデル 名前探しリッチなドメインモデル 名前探し
リッチなドメインモデル 名前探し
増田 亨
 
ラムダ計算入門
ラムダ計算入門ラムダ計算入門
ラムダ計算入門
Eita Sugimoto
 
エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織
Takafumi ONAKA
 
子供の言語獲得と機械の言語獲得
子供の言語獲得と機械の言語獲得子供の言語獲得と機械の言語獲得
子供の言語獲得と機械の言語獲得
Yuya Unno
 
それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?
Yoshitaka Kawashima
 
OSを手作りするという趣味と仕事
OSを手作りするという趣味と仕事OSを手作りするという趣味と仕事
OSを手作りするという趣味と仕事
uchan_nos
 
情報抽出入門 〜非構造化データを構造化させる技術〜
情報抽出入門 〜非構造化データを構造化させる技術〜情報抽出入門 〜非構造化データを構造化させる技術〜
情報抽出入門 〜非構造化データを構造化させる技術〜Yuya Unno
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ増田 亨
 
フロー効率性とリソース効率性について #xpjug
フロー効率性とリソース効率性について #xpjugフロー効率性とリソース効率性について #xpjug
フロー効率性とリソース効率性について #xpjug
Itsuki Kuroda
 
失敗から学ぶ機械学習応用
失敗から学ぶ機械学習応用失敗から学ぶ機械学習応用
失敗から学ぶ機械学習応用
Hiroyuki Masuda
 

What's hot (20)

不遇の標準ライブラリ - valarray
不遇の標準ライブラリ - valarray不遇の標準ライブラリ - valarray
不遇の標準ライブラリ - valarray
 
プログラムを高速化する話
プログラムを高速化する話プログラムを高速化する話
プログラムを高速化する話
 
C++でできる!OS自作入門
C++でできる!OS自作入門C++でできる!OS自作入門
C++でできる!OS自作入門
 
メタプログラミングって何だろう
メタプログラミングって何だろうメタプログラミングって何だろう
メタプログラミングって何だろう
 
リクルート式 自然言語処理技術の適応事例紹介
リクルート式 自然言語処理技術の適応事例紹介リクルート式 自然言語処理技術の適応事例紹介
リクルート式 自然言語処理技術の適応事例紹介
 
Portacle : Common Lispのオールインワン開発環境
Portacle : Common Lispのオールインワン開発環境Portacle : Common Lispのオールインワン開発環境
Portacle : Common Lispのオールインワン開発環境
 
「いい検索」を考える
「いい検索」を考える「いい検索」を考える
「いい検索」を考える
 
Pythonによる黒魔術入門
Pythonによる黒魔術入門Pythonによる黒魔術入門
Pythonによる黒魔術入門
 
20160526 依存関係逆転の原則
20160526 依存関係逆転の原則20160526 依存関係逆転の原則
20160526 依存関係逆転の原則
 
5分で解るセキュアコーディング
5分で解るセキュアコーディング5分で解るセキュアコーディング
5分で解るセキュアコーディング
 
リッチなドメインモデル 名前探し
リッチなドメインモデル 名前探しリッチなドメインモデル 名前探し
リッチなドメインモデル 名前探し
 
ラムダ計算入門
ラムダ計算入門ラムダ計算入門
ラムダ計算入門
 
エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織
 
子供の言語獲得と機械の言語獲得
子供の言語獲得と機械の言語獲得子供の言語獲得と機械の言語獲得
子供の言語獲得と機械の言語獲得
 
それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?
 
OSを手作りするという趣味と仕事
OSを手作りするという趣味と仕事OSを手作りするという趣味と仕事
OSを手作りするという趣味と仕事
 
情報抽出入門 〜非構造化データを構造化させる技術〜
情報抽出入門 〜非構造化データを構造化させる技術〜情報抽出入門 〜非構造化データを構造化させる技術〜
情報抽出入門 〜非構造化データを構造化させる技術〜
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ
 
フロー効率性とリソース効率性について #xpjug
フロー効率性とリソース効率性について #xpjugフロー効率性とリソース効率性について #xpjug
フロー効率性とリソース効率性について #xpjug
 
失敗から学ぶ機械学習応用
失敗から学ぶ機械学習応用失敗から学ぶ機械学習応用
失敗から学ぶ機械学習応用
 

Similar to TypeScript & 関数型講座 第3回 関数型入門

Functional Programming in Swift
Functional Programming in SwiftFunctional Programming in Swift
Functional Programming in SwiftKaz Yoshikawa
 
RubyとJavaScriptに見る第一級関数
RubyとJavaScriptに見る第一級関数RubyとJavaScriptに見る第一級関数
RubyとJavaScriptに見る第一級関数
Altech Takeno
 
関数プログラミング入門
関数プログラミング入門関数プログラミング入門
関数プログラミング入門
masatora atarashi
 
たのしい関数型
たのしい関数型たのしい関数型
たのしい関数型
Shinichi Kozake
 
Javascriptで学ぶ Functional Programming
Javascriptで学ぶ Functional ProgrammingJavascriptで学ぶ Functional Programming
Javascriptで学ぶ Functional Programming
todorokit
 
関数型都市忘年会『はじめての函数型プログラミング』
関数型都市忘年会『はじめての函数型プログラミング』関数型都市忘年会『はじめての函数型プログラミング』
関数型都市忘年会『はじめての函数型プログラミング』
Kenta USAMI
 
Scala の関数型プログラミングを支える技術
Scala の関数型プログラミングを支える技術Scala の関数型プログラミングを支える技術
Scala の関数型プログラミングを支える技術
Naoki Aoyama
 
Scalaプログラミング・マニアックス
Scalaプログラミング・マニアックスScalaプログラミング・マニアックス
Scalaプログラミング・マニアックスTomoharu ASAMI
 
関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)
啓 小笠原
 
Java8 lambdas chapter1_2
Java8 lambdas chapter1_2Java8 lambdas chapter1_2
Java8 lambdas chapter1_2
yo0824
 
たのしい高階関数
たのしい高階関数たのしい高階関数
たのしい高階関数
Shinichi Kozake
 
【Topotal輪読会】JavaScript で学ぶ関数型プログラミング 2 章
【Topotal輪読会】JavaScript で学ぶ関数型プログラミング 2 章【Topotal輪読会】JavaScript で学ぶ関数型プログラミング 2 章
【Topotal輪読会】JavaScript で学ぶ関数型プログラミング 2 章
YOSHIKAWA Ryota
 
[Basic 12] 関数型言語 / 型理論
[Basic 12] 関数型言語 / 型理論[Basic 12] 関数型言語 / 型理論
[Basic 12] 関数型言語 / 型理論
Yuto Takei
 
磯野ー!関数型言語やろうぜー!
磯野ー!関数型言語やろうぜー!磯野ー!関数型言語やろうぜー!
磯野ー!関数型言語やろうぜー!
Ra Zon
 
Lisp tutorial for Pythonista : Day 2
Lisp tutorial for Pythonista : Day 2Lisp tutorial for Pythonista : Day 2
Lisp tutorial for Pythonista : Day 2
Ransui Iso
 
初心者講習会資料(Osaka.r#6)
初心者講習会資料(Osaka.r#6)初心者講習会資料(Osaka.r#6)
初心者講習会資料(Osaka.r#6)Masahiro Hayashi
 
Scalaで萌える関数型プログラミング[1.1.RC1]
Scalaで萌える関数型プログラミング[1.1.RC1]Scalaで萌える関数型プログラミング[1.1.RC1]
Scalaで萌える関数型プログラミング[1.1.RC1]Ra Zon
 
Matlab講習2021
Matlab講習2021Matlab講習2021
Matlab講習2021
Tomoya Kamimura
 
第3回Rを使って統計分析を勉強する会
第3回Rを使って統計分析を勉強する会第3回Rを使って統計分析を勉強する会
第3回Rを使って統計分析を勉強する会
Nobuto Inoguchi
 

Similar to TypeScript & 関数型講座 第3回 関数型入門 (20)

Functional Programming in Swift
Functional Programming in SwiftFunctional Programming in Swift
Functional Programming in Swift
 
RubyとJavaScriptに見る第一級関数
RubyとJavaScriptに見る第一級関数RubyとJavaScriptに見る第一級関数
RubyとJavaScriptに見る第一級関数
 
関数プログラミング入門
関数プログラミング入門関数プログラミング入門
関数プログラミング入門
 
たのしい関数型
たのしい関数型たのしい関数型
たのしい関数型
 
Javascriptで学ぶ Functional Programming
Javascriptで学ぶ Functional ProgrammingJavascriptで学ぶ Functional Programming
Javascriptで学ぶ Functional Programming
 
関数型都市忘年会『はじめての函数型プログラミング』
関数型都市忘年会『はじめての函数型プログラミング』関数型都市忘年会『はじめての函数型プログラミング』
関数型都市忘年会『はじめての函数型プログラミング』
 
Scala の関数型プログラミングを支える技術
Scala の関数型プログラミングを支える技術Scala の関数型プログラミングを支える技術
Scala の関数型プログラミングを支える技術
 
Scalaプログラミング・マニアックス
Scalaプログラミング・マニアックスScalaプログラミング・マニアックス
Scalaプログラミング・マニアックス
 
関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)
 
Java8 lambdas chapter1_2
Java8 lambdas chapter1_2Java8 lambdas chapter1_2
Java8 lambdas chapter1_2
 
たのしい高階関数
たのしい高階関数たのしい高階関数
たのしい高階関数
 
【Topotal輪読会】JavaScript で学ぶ関数型プログラミング 2 章
【Topotal輪読会】JavaScript で学ぶ関数型プログラミング 2 章【Topotal輪読会】JavaScript で学ぶ関数型プログラミング 2 章
【Topotal輪読会】JavaScript で学ぶ関数型プログラミング 2 章
 
[Basic 12] 関数型言語 / 型理論
[Basic 12] 関数型言語 / 型理論[Basic 12] 関数型言語 / 型理論
[Basic 12] 関数型言語 / 型理論
 
磯野ー!関数型言語やろうぜー!
磯野ー!関数型言語やろうぜー!磯野ー!関数型言語やろうぜー!
磯野ー!関数型言語やろうぜー!
 
Lisp tutorial for Pythonista : Day 2
Lisp tutorial for Pythonista : Day 2Lisp tutorial for Pythonista : Day 2
Lisp tutorial for Pythonista : Day 2
 
初心者講習会資料(Osaka.r#6)
初心者講習会資料(Osaka.r#6)初心者講習会資料(Osaka.r#6)
初心者講習会資料(Osaka.r#6)
 
Scalaで萌える関数型プログラミング[1.1.RC1]
Scalaで萌える関数型プログラミング[1.1.RC1]Scalaで萌える関数型プログラミング[1.1.RC1]
Scalaで萌える関数型プログラミング[1.1.RC1]
 
Matlab講習2021
Matlab講習2021Matlab講習2021
Matlab講習2021
 
ATN No.2 Scala事始め
ATN No.2 Scala事始めATN No.2 Scala事始め
ATN No.2 Scala事始め
 
第3回Rを使って統計分析を勉強する会
第3回Rを使って統計分析を勉強する会第3回Rを使って統計分析を勉強する会
第3回Rを使って統計分析を勉強する会
 

TypeScript & 関数型講座 第3回 関数型入門