関数型軽い紹介

37
序文 関数型言語 . . 1 序文 パラダイムの紹介 命令型の問題点 . . 2 関数型の紹介 . . 3 関数型のフィーチャー 第一級関数 再帰 . . 4 関数型言語の問題点 状態がない パーフォマンス Daniel Perez 関数型言語 2013年12月20日 1 / 21

description

勉強会の資料

Transcript of 関数型軽い紹介

Page 1: 関数型軽い紹介

序文

関数型言語

...1 序文パラダイムの紹介命令型の問題点

...2 関数型の紹介

...3 関数型のフィーチャー第一級関数再帰

...4 関数型言語の問題点状態がないパーフォマンス

Daniel Perez 関数型言語 2013年12月20日 1 / 21

Page 2: 関数型軽い紹介

序文 パラダイムの紹介

パラダイム

.パラダイムとは..

......

プログラミングにおける「考え方」・「見方」プログラムが状態を持つのかプログラムはどう分割するか

クラスとオブジェクトで分けるかプロシージャで分けるか数学的な意味の関数で分けるか

副作用を許すかなどなど

Daniel Perez 関数型言語 2013年12月20日 2 / 21

Page 3: 関数型軽い紹介

序文 パラダイムの紹介

パラダイムについて.パラダイムのファクト..

......

パラダイムは山ほどある複数のパラダイムに対応するとが多い(マルチパラダイム)どう使うかはプログラマーの自由

.有名なパラダイム..

......

命令型プログラミング (C, Fortran, Basicなど)オブジェクト指向プログラミング (SmallTalk, Javaなど)関数型プログラミング (Haskell, ML系など)論理型プログラミング (Prolog, Datalogなど)記号型プログラミング (Lisp系など)

Daniel Perez 関数型言語 2013年12月20日 3 / 21

Page 4: 関数型軽い紹介

序文 パラダイムの紹介

命令型プログラミング.原理..

......

文が順番に実行されていく文でプログラムの状態を変えていく「何を」ではなく「どうやって」を中心に一般的に複数のプロシージャで組まれる� �

long f a c t o r i a l (long n){int i , r e su l t = 1;for( i = 2; i <= n ; i < n){resu l t *= i ;

}return re su l t ;

}� �命令型で階乗の計算

Daniel Perez 関数型言語 2013年12月20日 4 / 21

Page 5: 関数型軽い紹介

序文 パラダイムの紹介

オブジェクト指向プログラミング.原理..

......

プログラムはオブジェクトの組み合わせオブジェクトはデータを持つオブジェクトはプロシージャを持つオブジェクトは一般的にクラスのインスタンス� �

class Integerdef f a c t o r i a l(2 . upto self) . i n j ec t (& : * )endend5. f a c t o r i a l� �

オブジェクト指向で階乗の計算

Daniel Perez 関数型言語 2013年12月20日 5 / 21

Page 6: 関数型軽い紹介

序文 命令型の問題点

命令型の問題点

.サイド・エフェクト..

......

プログラム状態が変わっていく呼び出すタイミングや回数で影響を受けるプログラムが分かりづらくなる分散処理や自動化が難しくなる

Daniel Perez 関数型言語 2013年12月20日 6 / 21

Page 7: 関数型軽い紹介

関数型の紹介

関数型の基礎

関数型言語において, 数学的な意味での関数を扱う.

x! : N → N

x! =

{1 (x = 0)

x · (x− 1)! (その他)

� �def f ac t ( x : Long ) : Long = x match {case 0 => 1case _ => x * fac t ( x − 1)

}� �

Daniel Perez 関数型言語 2013年12月20日 7 / 21

Page 8: 関数型軽い紹介

関数型の紹介

関数型の基礎

関数型言語において, 数学的な意味での関数を扱う.

x! : N → N

x! =

{1 (x = 0)

x · (x− 1)! (その他)

� �def f ac t ( x : Long ) : Long = x match {case 0 => 1case _ => x * fac t ( x − 1)

}� �Daniel Perez 関数型言語 2013年12月20日 7 / 21

Page 9: 関数型軽い紹介

関数型の紹介

数学的な意味での関数.性質..

......

サイド・エフェクトがない1つの入力に対して, 出力は絶対に変わらないデータが状態を持たない参照透過性を持つ

Daniel Perez 関数型言語 2013年12月20日 8 / 21

Page 10: 関数型軽い紹介

関数型の紹介

関数型言語関数型言語におけるプログラムは関数の組み合わせにすぎない関数は入力を変えない. 新しい出力を生成する

Daniel Perez 関数型言語 2013年12月20日 9 / 21

Page 11: 関数型軽い紹介

関数型の紹介

関数型言語関数型言語におけるプログラムは関数の組み合わせにすぎない関数は入力を変えない. 新しい出力を生成する

Daniel Perez 関数型言語 2013年12月20日 9 / 21

Page 12: 関数型軽い紹介

関数型のフィーチャー

関数型のフィーチャー

命令型のフィーチャーだけで以上の書き方はほぼ不可能関数型言語が新しい概念やフィーチャーを導入した現在関数型言語でない言語でも取り入れられてるフィーチャーもある

.フィーチャ一覧..

......

第一級関数高階関数カリー化関数の部分適用遅延評価などなど

Daniel Perez 関数型言語 2013年12月20日 10 / 21

Page 13: 関数型軽い紹介

関数型のフィーチャー

関数型のフィーチャー

命令型のフィーチャーだけで以上の書き方はほぼ不可能関数型言語が新しい概念やフィーチャーを導入した現在関数型言語でない言語でも取り入れられてるフィーチャーもある

.フィーチャ一覧..

......

第一級関数高階関数カリー化関数の部分適用遅延評価などなど

Daniel Perez 関数型言語 2013年12月20日 10 / 21

Page 14: 関数型軽い紹介

関数型のフィーチャー 第一級関数

高階関数

関数は他の型と同じ扱いかたができる関数を別の関数に渡すこともできる� �

val l i s t = L i s t (1 , 2 , 3)def square ( x : In t ) = x * xl i s t map square / / L ist (1 , 4 , 9)/ / postfixOps are l e f t associativel i s t map square foreach pr in t ln / / 1\n4 \n9/ / l i s t .map( square ) . foreach ( print ln )� �

Daniel Perez 関数型言語 2013年12月20日 11 / 21

Page 15: 関数型軽い紹介

関数型のフィーチャー 第一級関数

カリー化

非カリー化の関数

f : (X × Y ) → Z

カリー化の関数

f : X → (Y → Z)

� �def withWriter ( f i l e : F i l e ) ( block : BufferedWriter =>

Unit ) = . . . .withWriter (new F i l e ( " foobar " ) ) { out => out wr i te "

foobar " }� �

Daniel Perez 関数型言語 2013年12月20日 12 / 21

Page 16: 関数型軽い紹介

関数型のフィーチャー 第一級関数

カリー化

非カリー化の関数

f : (X × Y ) → Z

カリー化の関数

f : X → (Y → Z)� �def withWriter ( f i l e : F i l e ) ( block : BufferedWriter =>

Unit ) = . . . .withWriter (new F i l e ( " foobar " ) ) { out => out wr i te "

foobar " }� �Daniel Perez 関数型言語 2013年12月20日 12 / 21

Page 17: 関数型軽い紹介

関数型のフィーチャー 第一級関数

部分適用

関数が関数を返す

f : X → (Y → Z)

⇒∀x ∈ X, f(x) ∈ ZY

� �def withWriter ( f i l e : F i l e ) ( block : BufferedWriter =>

Unit ) = . . . .val fooWriter = withWriter (new F i l e ( " foo " ) )fooWriter { out => out p r in t ln " foobar " }fooWriter { out => out p r in t ln "barbaz" }� �

Daniel Perez 関数型言語 2013年12月20日 13 / 21

Page 18: 関数型軽い紹介

関数型のフィーチャー 第一級関数

部分適用

関数が関数を返す

f : X → (Y → Z)

⇒∀x ∈ X, f(x) ∈ ZY

� �def withWriter ( f i l e : F i l e ) ( block : BufferedWriter =>

Unit ) = . . . .val fooWriter = withWriter (new F i l e ( " foo " ) )fooWriter { out => out p r in t ln " foobar " }fooWriter { out => out p r in t ln "barbaz" }� �

Daniel Perez 関数型言語 2013年12月20日 13 / 21

Page 19: 関数型軽い紹介

関数型のフィーチャー 再帰

再帰の紹介

.再帰を使う理由..

......

状態が変わらない→for(int i = 0; i < N; i++)は書けない

命令型言語でよく使われているループは基本的に使えない代わりに再帰的に定義することが一般的

.再帰の基本..

......

基底段階: ここまで来たら関数を止める帰納段階: 処理して, 再帰的に呼び出す段階

Daniel Perez 関数型言語 2013年12月20日 14 / 21

Page 20: 関数型軽い紹介

関数型のフィーチャー 再帰

再帰の紹介

.再帰を使う理由..

......

状態が変わらない→for(int i = 0; i < N; i++)は書けない命令型言語でよく使われているループは基本的に使えない

代わりに再帰的に定義することが一般的

.再帰の基本..

......

基底段階: ここまで来たら関数を止める帰納段階: 処理して, 再帰的に呼び出す段階

Daniel Perez 関数型言語 2013年12月20日 14 / 21

Page 21: 関数型軽い紹介

関数型のフィーチャー 再帰

再帰の紹介

.再帰を使う理由..

......

状態が変わらない→for(int i = 0; i < N; i++)は書けない命令型言語でよく使われているループは基本的に使えない代わりに再帰的に定義することが一般的

.再帰の基本..

......

基底段階: ここまで来たら関数を止める帰納段階: 処理して, 再帰的に呼び出す段階

Daniel Perez 関数型言語 2013年12月20日 14 / 21

Page 22: 関数型軽い紹介

関数型のフィーチャー 再帰

再帰の紹介

.再帰を使う理由..

......

状態が変わらない→for(int i = 0; i < N; i++)は書けない命令型言語でよく使われているループは基本的に使えない代わりに再帰的に定義することが一般的

.再帰の基本..

......

基底段階: ここまで来たら関数を止める帰納段階: 処理して, 再帰的に呼び出す段階

Daniel Perez 関数型言語 2013年12月20日 14 / 21

Page 23: 関数型軽い紹介

関数型のフィーチャー 再帰

再帰の例

.階乗..

......x! =

{1 (x = 0)

x · (x− 1)! (その他)

� �def f ac t ( x : Long ) : Long = x match {case 0 => 1case _ => x * fac t ( x − 1)

}� �

Daniel Perez 関数型言語 2013年12月20日 15 / 21

Page 24: 関数型軽い紹介

関数型のフィーチャー 再帰

再帰の例

.drop関数..

......

drop(2, [1, 2, 3, 4])= [3, 4]

f(x, {a1, · · · , an}) =

{{a1, · · · , an} (x = 0)

f((x− 1), {a2, · · · , an}) (x > 0)

� �def drop [A ] ( n : Int , l i s t : L i s t [A ] ) : L i s t [A ] = n match {case 0 => l i s tcase _ => drop (n − 1 , l i s t . t a i l )� �

Daniel Perez 関数型言語 2013年12月20日 16 / 21

Page 25: 関数型軽い紹介

関数型のフィーチャー 再帰

再帰の例

.drop関数..

......

drop(2, [1, 2, 3, 4])= [3, 4]

f(x, {a1, · · · , an}) =

{{a1, · · · , an} (x = 0)

f((x− 1), {a2, · · · , an}) (x > 0)

� �def drop [A ] ( n : Int , l i s t : L i s t [A ] ) : L i s t [A ] = n match {case 0 => l i s tcase _ => drop (n − 1 , l i s t . t a i l )� �

Daniel Perez 関数型言語 2013年12月20日 16 / 21

Page 26: 関数型軽い紹介

関数型のフィーチャー 再帰

再帰の例.map関数..

......

map(f, [1, 2, 3])= [f(1), f(2), f(3)]

S, Tは任意の集合X = {a1, · · · , an} ⊂ S

m : T S ×X → Y ⊂ T

m(f, {a1, · · · , an}) =

{∅ (X = ∅)

{f(a1)}∪

m(f, {a2, · · · , an}) (その他)

� �def map[A , B ] ( f : A => B, l i s t : L i s t [A ] ) : L i s t [B ] = l i s t match {case Ni l => Ni lcase head : : t a i l => f (head ) : : map( f , t a i l )

}� �

Daniel Perez 関数型言語 2013年12月20日 17 / 21

Page 27: 関数型軽い紹介

関数型のフィーチャー 再帰

再帰の例.map関数..

......

map(f, [1, 2, 3])= [f(1), f(2), f(3)]

S, Tは任意の集合X = {a1, · · · , an} ⊂ S

m : T S ×X → Y ⊂ T

m(f, {a1, · · · , an}) =

{∅ (X = ∅)

{f(a1)}∪

m(f, {a2, · · · , an}) (その他)

� �def map[A , B ] ( f : A => B, l i s t : L i s t [A ] ) : L i s t [B ] = l i s t match {case Ni l => Ni lcase head : : t a i l => f (head ) : : map( f , t a i l )

}� �Daniel Perez 関数型言語 2013年12月20日 17 / 21

Page 28: 関数型軽い紹介

関数型のフィーチャー 再帰

名前呼び (Call by name)

関数呼び出し時に結果まだ評価しなくて良い関数内で始めて値を使う時に評価する

� �def f = { p r in t ln ( " ca l l f " ) ; 1 }� �� �def fByValue (n : In t ) = {

p r in t ln ( " cal l ing fByValue" )p r in t ln ( s "x1 = $n" )p r in t ln ( s "x2 = $n" )

}fByValue ( f )� �

� �def fByName(n : => In t ) = {

p r in t ln ( " cal l ing fByName" )p r in t ln ( s "x1 = $n" )p r in t ln ( s "x2 = $n" )

}fByName( f )� �� �

ca l l fca l l i ng fByValuex1 = 1x2 = 1� �

� �ca l l i ng fByNameca l l fx1 = 1ca l l fx2 = 1� �

Daniel Perez 関数型言語 2013年12月20日 18 / 21

Page 29: 関数型軽い紹介

関数型のフィーチャー 再帰

名前呼び (Call by name)

関数呼び出し時に結果まだ評価しなくて良い関数内で始めて値を使う時に評価する� �

def f = { p r in t ln ( " ca l l f " ) ; 1 }� �

� �def fByValue (n : In t ) = {

p r in t ln ( " cal l ing fByValue" )p r in t ln ( s "x1 = $n" )p r in t ln ( s "x2 = $n" )

}fByValue ( f )� �

� �def fByName(n : => In t ) = {

p r in t ln ( " cal l ing fByName" )p r in t ln ( s "x1 = $n" )p r in t ln ( s "x2 = $n" )

}fByName( f )� �� �

ca l l fca l l i ng fByValuex1 = 1x2 = 1� �

� �ca l l i ng fByNameca l l fx1 = 1ca l l fx2 = 1� �

Daniel Perez 関数型言語 2013年12月20日 18 / 21

Page 30: 関数型軽い紹介

関数型のフィーチャー 再帰

名前呼び (Call by name)

関数呼び出し時に結果まだ評価しなくて良い関数内で始めて値を使う時に評価する� �

def f = { p r in t ln ( " ca l l f " ) ; 1 }� �� �def fByValue (n : In t ) = {

p r in t ln ( " cal l ing fByValue" )p r in t ln ( s "x1 = $n" )p r in t ln ( s "x2 = $n" )

}fByValue ( f )� �

� �def fByName(n : => In t ) = {

p r in t ln ( " cal l ing fByName" )p r in t ln ( s "x1 = $n" )p r in t ln ( s "x2 = $n" )

}fByName( f )� �� �

ca l l fca l l i ng fByValuex1 = 1x2 = 1� �

� �ca l l i ng fByNameca l l fx1 = 1ca l l fx2 = 1� �

Daniel Perez 関数型言語 2013年12月20日 18 / 21

Page 31: 関数型軽い紹介

関数型のフィーチャー 再帰

名前呼び (Call by name)

関数呼び出し時に結果まだ評価しなくて良い関数内で始めて値を使う時に評価する� �

def f = { p r in t ln ( " ca l l f " ) ; 1 }� �� �def fByValue (n : In t ) = {

p r in t ln ( " cal l ing fByValue" )p r in t ln ( s "x1 = $n" )p r in t ln ( s "x2 = $n" )

}fByValue ( f )� �

� �def fByName(n : => In t ) = {

p r in t ln ( " cal l ing fByName" )p r in t ln ( s "x1 = $n" )p r in t ln ( s "x2 = $n" )

}fByName( f )� �

� �ca l l fca l l i ng fByValuex1 = 1x2 = 1� �

� �ca l l i ng fByNameca l l fx1 = 1ca l l fx2 = 1� �

Daniel Perez 関数型言語 2013年12月20日 18 / 21

Page 32: 関数型軽い紹介

関数型のフィーチャー 再帰

名前呼び (Call by name)

関数呼び出し時に結果まだ評価しなくて良い関数内で始めて値を使う時に評価する� �

def f = { p r in t ln ( " ca l l f " ) ; 1 }� �� �def fByValue (n : In t ) = {

p r in t ln ( " cal l ing fByValue" )p r in t ln ( s "x1 = $n" )p r in t ln ( s "x2 = $n" )

}fByValue ( f )� �

� �def fByName(n : => In t ) = {

p r in t ln ( " cal l ing fByName" )p r in t ln ( s "x1 = $n" )p r in t ln ( s "x2 = $n" )

}fByName( f )� �� �

ca l l fca l l i ng fByValuex1 = 1x2 = 1� �

� �ca l l i ng fByNameca l l fx1 = 1ca l l fx2 = 1� �

Daniel Perez 関数型言語 2013年12月20日 18 / 21

Page 33: 関数型軽い紹介

関数型のフィーチャー 再帰

名前呼び (Call by name)

関数呼び出し時に結果まだ評価しなくて良い関数内で始めて値を使う時に評価する� �

def f = { p r in t ln ( " ca l l f " ) ; 1 }� �� �def fByValue (n : In t ) = {

p r in t ln ( " cal l ing fByValue" )p r in t ln ( s "x1 = $n" )p r in t ln ( s "x2 = $n" )

}fByValue ( f )� �

� �def fByName(n : => In t ) = {

p r in t ln ( " cal l ing fByName" )p r in t ln ( s "x1 = $n" )p r in t ln ( s "x2 = $n" )

}fByName( f )� �� �

ca l l fca l l i ng fByValuex1 = 1x2 = 1� �

� �ca l l i ng fByNameca l l fx1 = 1ca l l fx2 = 1� �

Daniel Perez 関数型言語 2013年12月20日 18 / 21

Page 34: 関数型軽い紹介

関数型のフィーチャー 再帰

遅延評価 (Lazy evaluation)

値が必要になった時のみ評価されるScalaではlazyで明示的に使う� �

object DB {lazy val connection = . . .

}� �� �def f i b : Stream [ In t ] = 0 #: : f i b . scanLeft (1 ) { _ + _ }f i b take 10 toL i s t� �

Daniel Perez 関数型言語 2013年12月20日 19 / 21

Page 35: 関数型軽い紹介

関数型言語の問題点 状態がない

状態がない

.問題..

......

実際作るほとんどのものにおいて, 何かしら状態を持つデータベースのモデルユーザーのセッション

参照透過性と状態を両立させることが難しい

.解決..

......

参照透過性を部分的になくすモナドを使う

Daniel Perez 関数型言語 2013年12月20日 20 / 21

Page 36: 関数型軽い紹介

関数型言語の問題点 状態がない

状態がない

.問題..

......

実際作るほとんどのものにおいて, 何かしら状態を持つデータベースのモデルユーザーのセッション

参照透過性と状態を両立させることが難しい

.解決..

......

参照透過性を部分的になくすモナドを使う

Daniel Perez 関数型言語 2013年12月20日 20 / 21

Page 37: 関数型軽い紹介

関数型言語の問題点 パーフォマンス

パーフォマンス

ハードウェアがミュータブルのデータに向いているC言語の配列の読み・書き込みは非常に速い

コンパイル時に最適化してもその性能に近づくことが難しい

Daniel Perez 関数型言語 2013年12月20日 21 / 21