Slide 1

Slide 1 text

Functional Way

Slide 2

Slide 2 text

自己紹介: lagénorhynque

Slide 3

Slide 3 text

( d e f p r o f i l e l a g é n o r h y n q u e [ K e n t O H A S H I ] : g i t h u b / t w i t t e r @ l a g e n o r h y n q u e : c o m p a n y 株式会社オプト : l a n g u a g e s [ C l o j u r e H a s k e l l P y t h o n S c a l a G o E n g l i s h f r a n ç a i s D e u t s c h р у с с к и й ] : i n t e r e s t s [ プログラミング 語学 数学] )

Slide 4

Slide 4 text

「 フィボナッチ数」( ) の計算を例に Fibonacci number 関数型プログラミングの基本的な概念を紹介 1. 再帰 (recursion) 2. 末尾再帰 (tail recursion) 3. 高階関数 (higher-order function) 4. 遅延評価 (lazy evaluation)

Slide 5

Slide 5 text

フィボナッチ数 番目のフィボナッチ数 は、 以下のように定義される。 i F i F 0 F 1 F i = = = 0 1 + , i ≥ 2 F i −2 F i −1 と続き、 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, . . . 直前の2 項の和が次の項になっている。

Slide 6

Slide 6 text

0. ルー プ 手続き型( ) 言語の基本パター ン procedural # P y t h o n d e f f i b o n a c c i ( i ) : a , b = 0 , 1 f o r n i n r a n g e ( i ) : a , b = b , a + b r e t u r n a 副作用( ) 命令型( ) side e ect imperative

Slide 7

Slide 7 text

変数やルー プ構造が目立ち、 数学的な定義( プログラムの仕様) との関 係が分かりづらい 登場する変数が多くなったり、 処理が複雑になったりすると、 状態の 変化をたどるのが困難になりうる

Slide 8

Slide 8 text

1. 再帰 ( ) recursion 関数型( ) 言語の基本パター ン functional - - H a s k e l l f i b o n a c c i 1 : : I n t - > I n t e g e r f i b o n a c c i 1 0 = 0 f i b o n a c c i 1 1 = 1 f i b o n a c c i 1 i = f i b o n a c c i 1 ( i - 2 ) + f i b o n a c c i 1 ( i - 1 ) ; ; C l o j u r e ( d e f n f i b o n a c c i 1 [ i ] ( c o n d ( = i 0 ) 0 N ( = i 1 ) 1 N : e l s e ( + ( f i b o n a c c i 1 ( - i 2 ) ) ( f i b o n a c c i 1 ( - i 1 ) ) ) ) ) パター ンマッチング( ) 宣言型( ) 参照透過性( ) pattern matching declarative referential transparency

Slide 9

Slide 9 text

数学的な再帰的定義をほぼそのまま表現した、 シンプルなコー ド 可変状態がないため状態の変化を管理する必要がなくなり、 並列/ 並 行処理として実行するのも比較的容易 関数呼出しの繰り返しによりスタックオー バー フロー が発生する可能 性がある フィボナッチ数の場合、 同一の計算が繰り返されて計算量が指数的に 増大してしまう→ メモ化( ) を検討 memoization

Slide 10

Slide 10 text

2. 末尾再帰 ( ) tail recursion 関数内部で最後に実行される処理が再帰呼出しになっている再帰 - - H a s k e l l f i b o n a c c i 2 : : I n t - > I n t e g e r f i b o n a c c i 2 i = f i b i 0 1 w h e r e f i b 0 a _ = a f i b n a b = f i b ( n - 1 ) b ( a + b ) ; ; C l o j u r e ( d e f n f i b o n a c c i 2 [ i ] ( l e t f n [ ( f i b [ n a b ] ( i f ( z e r o ? n ) a ( r e c u r ( d e c n ) b ( + a b ) ) ) ) ] ( f i b i 0 N 1 N ) ) )

Slide 11

Slide 11 text

多くの関数型言語では末尾再帰関数が末尾呼出し最適化(tail call optimization) により命令型のルー プと同等の処理に変換され、 スタ ックオー バー フロー が防止できる コー ドの処理内容も命令型ルー プによく似ている

Slide 12

Slide 12 text

3. 高階関数 ( ) higher-order function 引数として関数を受け取る、 または戻り値として関数を返す関数 - - H a s k e l l f i b o n a c c i 3 : : I n t - > I n t e g e r f i b o n a c c i 3 i = f s t $ f o l d l ' f i b ( 0 , 1 ) [ 1 . . i ] w h e r e f i b ( a , b ) _ = ( b , a + b ) ; ; C l o j u r e ( d e f n f i b o n a c c i 3 [ i ] ( l e t f n [ ( f i b [ [ a b ] _ ] [ b ( + a b ) ] ) ] ( f i r s t ( r e d u c e f i b [ 0 N 1 N ] ( r a n g e 0 i ) ) ) ) )

Slide 13

Slide 13 text

典型的な繰り返し処理は抽象化されたライブラリの高階関数に任せ、 固有のロジックを持った関数の実装に集中することで、 効率良くコー ディングすることができ、 コー ドの可読性も向上する オブジェクト指向プログラミングのデザインパター ンの多くは高階関 数によって同等の目的を果たせる

Slide 14

Slide 14 text

4. 遅延評価 ( ) lazy evaluation 式の評価を計算で必要になるまで遅らせる評価戦略 cf. 先行評価( ) eager evaluation - - H a s k e l l f i b o n a c c i 4 : : I n t - > I n t e g e r f i b o n a c c i 4 i = f i b s ! ! i w h e r e f i b s = m a p f s t $ i t e r a t e ( \ ( a , b ) - > ( b , a + b ) ) ( 0 , 1 ) ; ; C l o j u r e ( d e f n f i b o n a c c i 4 [ i ] ( l e t [ f i b s ( m a p f i r s t ( i t e r a t e ( f n [ [ a b ] ] [ b ( + a b ) ] ) [ 0 N 1 N ] ) ) ] ( n t h f i b s i ) ) )

Slide 15

Slide 15 text

- - H a s k e l l f i b o n a c c i 5 : : I n t - > I n t e g e r f i b o n a c c i 5 i = f i b s ! ! i w h e r e f i b s = 0 : 1 : z i p W i t h ( + ) f i b s ( t a i l f i b s ) ; ; C l o j u r e ( d e f n f i b o n a c c i 5 [ i ] ( l e t f n [ ( f i b s [ a b ] ( c o n s a ( l a z y - s e q ( f i b s b ( + a b ) ) ) ) ) ] ( n t h ( f i b s 0 N 1 N ) i ) ) )

Slide 16

Slide 16 text

Haskell では遅延評価がデフォルトの評価戦略 Clojure は先行評価が基本だが、 遅延評価されるシー ケンス( 遅延シー ケンス) が利用できる 特に巨大なデー タ構造や無限に続くデー タ構造を扱う場合に、 シンプ ルな定義と効率を両立させることができる

Slide 17

Slide 17 text

Further Reading Haskell 『 プログラミングHaskell』 『 すごいHaskell たのしく学ぼう!』 『 関数プログラミング実践入門』 Clojure 『 プログラミングClojure』 Exploring Clojure with Factorial Computation Scala 『Scala スケー ラブルプログラミング』 『Scala 関数型デザイン& プログラミング』

Slide 18

Slide 18 text

Erlang 『 すごいErlang ゆかいに学ぼう!』 Elixir 『 プログラミングElixir』 OCaml 『 プログラミングの基礎』 cf. 今回の発表の元ネタ: BasicsOfFunctionalProgramming.md