f#によるfunctional programming入門

35
F # による Functional Programming 入門 bleis-tift December 22 2012

Upload: bleis-tift

Post on 30-Jun-2015

6.139 views

Category:

Technology


4 download

DESCRIPTION

高専カンファ in 三重2の発表資料です。高専生向けなので、入門と言いつつアレな感じですので注意してください。

TRANSCRIPT

Page 1: F#によるFunctional Programming入門

F#によるFunctional Programming入門

bleis-tift

December 22 2012

Page 2: F#によるFunctional Programming入門

自己紹介

id:bleis-tift / @bleis

鈴鹿高専電子情報工学科卒業生

Microsoft MVP for Visual F#

Page 3: F#によるFunctional Programming入門

いきなりですが質問です

Q1. プログラミングしたことありますか?

Page 4: F#によるFunctional Programming入門

Q2. どんな言語を使いましたか?

C, C++, BASIC, Java, C#, PHP, Perl, Python,Ruby, JavaScript, ...授業だと大体こんなところでしょうか?

Page 5: F#によるFunctional Programming入門

今日話すこと

授業ではあまり取り上げられないであろうタイプの言語である、

関数型プログラミング言語

を取り上げ、関数プログラミングについて紹介します。

Page 6: F#によるFunctional Programming入門

その前に・・・

手続型言語ってなんでしょうか?手続きを記述する

処理のまとまりを「手続き」としてまとめる手続きを構成するのは「文」が基本

状態を書き換える基本的に変数は書き換え可能単純なループは変数の書き換えがほぼ必須

手続型言語は文中心かつ、書き換え可能な変数が必須

Page 7: F#によるFunctional Programming入門

手続型言語に対し・・・

関数型言語はざっくりこんな感じです。関数を記述する

処理のまとまりを「関数」としてまとめる関数を構成するのは「式」

状態の書き換えは局所化する基本的に変数は書き換え不可能変数の書き換えによらない繰り返し

関数型言語は式中心

Page 8: F#によるFunctional Programming入門

式と文の違い

式と文の違い、分かりますか?

式は評価することで値になる

文そのものは値を持たない

値が書けるところには式が書ける!

Page 9: F#によるFunctional Programming入門

式と文の違い (文)

.

Java

.

.

.

int[] f(int x) {

int[] res = new int[x];

for (int i = 0; i < x; i++)

res[i] = i * 2;

return res;

}

int sum(int[] xs) { ... }

// これはもちろん可能int total = sum(f(10));

// これは出来ないint total = sum(

int[] res = new int[x];

for (int i = 0; i < x; i++)

res[i] = i * 2;

return res;

);

Page 10: F#によるFunctional Programming入門

式と文の違い (式)

.

F#

.

.

.

let f x =

let res = Array.zeroCreate x

for i in 0..(x - 1) do

res.[i] <- i * 2

res

let sum xs = ...

// これはもちろん可能let total = sum(f 10)

// これも可能!let total =

sum (

let res = Array.zeroCreate 10

for i in 0..(10 - 1) do

res.[i] <- i * 2

res

)

Page 11: F#によるFunctional Programming入門

式中心であることの利点

式を組み合わせてより大きく複雑な式を構築できる!

Page 12: F#によるFunctional Programming入門

F#について

ちょっと休憩して、F#について。

Visual Studioに標準搭載されている、マルチパラダイム言語(コアとなるパラダイムは関数型)

.NET Framework上で動作するため、

.NETの資産を活かせる

強い静的型付き言語

インデントを文法に含む (軽量構文の場合)

オープンソース

Page 13: F#によるFunctional Programming入門

さっきのコードをもう一回見てみる

.

.

let f x =

let res = Array.zeroCreate x

for i in 0..(x - 1) do

res.[i] <- i * 2 // 状態書き換えてる!res

.

状態書き換えない版

.

.

.

let f x =

Array.init x ((*)2)

ループを自分で書く必要すらない!→バグの抑制につながる

Page 14: F#によるFunctional Programming入門

F#って静的型付き言語って言ったよね・・・?

今までのコード、型書いてません。でも、型推論によってコンパイル時に型が付いていたのです!

.

.

// intを受け取って int[]を返す関数// 「int -> int[]」と記述するlet f x =

Array.init x ((*)2)

この関数にどうやって型が付いたのか見ていきます。

Page 15: F#によるFunctional Programming入門

その前に

((*)2)って何!

Page 16: F#によるFunctional Programming入門

((*)2)について

F#では、中置演算子を関数として扱える

.

.

2 * 4 // 8

(*) 2 4 // 8

そして、複数引数の関数に引数を「一部」与えることができる

.

.

let f x y = x * y

f 2 4 // 8

let g = f 2

g 4 // 8

つまり、((*)2)は「何かを 2倍する関数」

Page 17: F#によるFunctional Programming入門

型推論のステップ

.

.

let f x =

Array.init x ((*)2)

.

..

1 Array.initは、int → (int → α) → α[]

.

.

.

2 xはArray.initの第一引数として渡しているxの型は int

.

.

.

3 戻り値の型はArray.initの戻り値の型と同じfの戻り値の型はα[]

.

.

.

4 掛け算「*」の型は int → int → int((*)2)は引数を一つ与えているので、int → intこれを Array.initの第二引数として渡しているので、(int → α)のαは int

全体として、fは「int → int[]」

Page 18: F#によるFunctional Programming入門

型推論の利点

型を書かなくても型が付く→型チェックの恩恵が受けられる

Page 19: F#によるFunctional Programming入門

ちょっと休憩

ここまでで何か質問ありますか?

Page 20: F#によるFunctional Programming入門

ここからは型について

AかBかCのどれかを表す型が欲しくなったときどうしますか?列挙型を使う?

.

Javaの例

.

.

.

enum T { A, B, C }

これでどうや!

Page 21: F#によるFunctional Programming入門

列挙型でダメな場合

列挙型は「Aの時のみ必要な情報」を保持できない例えば、

アンケートの項目「このイベントを何で知りましたか?」

Webサイト / Twitter / Facebook / その他

その他の場合は理由が必要

これは列挙型ではうまくあらわせない・・・

Page 22: F#によるFunctional Programming入門

どうしよう

.

列挙型とクラスでやる?

.

.

.

enum InfoSource {

WebSite, Twitter, Facebook, Etc

}

class Answer {

InfoSource source;

String etc;

...

}

Etc以外の時に etcが使われてしまうかもしれない

Page 23: F#によるFunctional Programming入門

どうしよう・・・クラス階層を作ってみる?

.

こうや!

.

.

.

interface InfoSource { }

enum WebSite implements InfoSource { Instance }

enum Twitter implements InfoSource { Instance }

enum Facebook implements InfoSource { Instance }

class Etc implements InfoSource {

String etc;

}

Etc以外の時は etcが使えない!

でも InfoSourceをEtcとして使うためにはキャストが必要

結局コンパイル時に解決できていない

そこでVisitorですよ!

Page 24: F#によるFunctional Programming入門

Visitor

.

Visitorの導入

.

.

.

interface Visitor {

void webSite(WebSite w);

void twitter(Twitter t);

void facebook(Facebook f);

void etc(Etc e);

}

interface InfoSource { void accept(Visitor v); }

enum WebSite implements InfoSource {

Instance;

public void accept(Visitor v) { return v.webSite(this); }

}

enum Twitter implements InfoSource {

Instance;

public void accept(Visitor v) { return v.twitter(this); }

}

enum Facebook implements InfoSource {

Instance;

public void accept(Visitor v) { return v.facebook(this); }

}

class Etc implements InfoSource {

String etc;

public void accept(Visitor v) { return v.etc(this); }

}

Page 25: F#によるFunctional Programming入門

やってられるかー!

Page 26: F#によるFunctional Programming入門

そこで直和型ですよ!

.

F#の直和型 (判別共用体)を使えばこの通り

.

.

.

type InfoSource =

| WebSite

| Twitter

| Facebook

| Etc of string

すっきり!

Page 27: F#によるFunctional Programming入門

使い方も簡単

.

match式を使う

.

.

.

let toStr src =

match src with

| WebSite -> "Webサイト"

| Twitter -> "Twitter"

| Facebook -> "Facebook"

| Etc etc -> "その他 (" + etc + ")"

.

function式でも可

.

.

.

let toStr = function

| WebSite -> "Webサイト"

| Twitter -> "Twitter"

| Facebook -> "Facebook"

| Etc etc -> "その他 (" + etc + ")"

Page 28: F#によるFunctional Programming入門

判別共用体のさらなる用途

ここまでは、列挙型に毛の生えたようなもの

ここまででも便利だが・・・

判別共用体は、自分自身を参照することで更に便利に!

Page 29: F#によるFunctional Programming入門

情報系ではおそらく一度は実装する

.

二分木

.

.

.

これを実装してみましょう

Page 30: F#によるFunctional Programming入門

二分木の実装

.

Javaの場合

.

.

.

public class BinTree {

final int value;

BinTree left = null;

BinTree right = null;

public BinTree(int value) {

this.value = value;

}

}

.

F#の場合

.

.

.

type BinTree =

| Leaf

| Node of BinTree * int * BinTree

// ↑ ↑

Page 31: F#によるFunctional Programming入門

二分探索木の探索

.

Javaの場合

.

.

.

public boolean contains(int value) {

if (value == this.value)

return true;

if (value < this.value && lelft != null)

return left.contains(value);

if (this.value < value && right != null)

return right.contains(value);

return false;

}

.

F#の場合

.

.

.

let rec contains value = function

| Leaf -> false

| Node (l, v, r) when v = value -> true

| Node (l, v, r) when value < v -> contains value l

| Node (l, v, r) when v < value -> contains value r

Page 32: F#によるFunctional Programming入門

両者の違い

F#の実装の方が短い (Javaよりも宣言的)

Java版は nullを使うため、NullPointerExceptionが起こりうるのに対し、F#版は nullを使わない

Java版は二分木の操作は参照をやりくりする必要があるのに対し、F#版はパターンマッチが使える

Page 33: F#によるFunctional Programming入門

判別共用体は

再帰的なデータ構造を上手に扱える再帰的なデータ構造は思いのほか多いリスト、木、ファイルシステム、などなど

簡単に記述できる型を定義するハードルが低い (型が軽い)

Page 34: F#によるFunctional Programming入門

取りこぼし

リストとリストの処理

高階関数 (関数が第一級の値)

少ないルールを組み合わせる

モナドとか

Page 35: F#によるFunctional Programming入門

まとめ

文より式!

直和型 (判別共用体)!

F#! F#!