関数型志向python - llまつり2013

102
関数型指向 Python LLまつり2013 / @esehara

Upload: esehara-shigeo

Post on 31-May-2015

9.559 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 関数型志向Python - LLまつり2013

関数型指向Python

LLまつり2013 / @esehara

Page 2: 関数型志向Python - LLまつり2013

お前誰だ

Page 3: 関数型志向Python - LLまつり2013

Esehara Shigeo(29)言語:Python

OS:Ubuntu + Amesome(タイル型)

好きなMonad: Maybe

気になる言語: Prolog所属: 株式会社マリーチ

Page 4: 関数型志向Python - LLまつり2013

このスライドは以下に、既にアップされているので

スライドを手元でみたいときは

http://www.slideshare.net/esehara/

から見てください

Page 5: 関数型志向Python - LLまつり2013

ところで皆さんに質問があります

Page 6: 関数型志向Python - LLまつり2013

関数型言語使って

ますか?

Page 7: 関数型志向Python - LLまつり2013

そもそも「関数型言語」

ってなんですか?

Page 8: 関数型志向Python - LLまつり2013

(eq? functional lisp)

=> #t / #f ?

Page 9: 関数型志向Python - LLまつり2013

(eq? functional lisp)

Page 10: 関数型志向Python - LLまつり2013

『計算機プログラムの構造と解釈』

特徴のもっとも著しいのはプロセスの手続き

(procedures)というLispによる記述自体が

Lispデータとして表現, 処理出来ることである.

(p. 2)

Page 11: 関数型志向Python - LLまつり2013

プロセスの手続きというLispによる

記述……?

Page 12: 関数型志向Python - LLまつり2013

手続きって関数型

と違うものなの?

Page 13: 関数型志向Python - LLまつり2013

抜き打ち調査

Page 14: 関数型志向Python - LLまつり2013
Page 15: 関数型志向Python - LLまつり2013
Page 16: 関数型志向Python - LLまつり2013
Page 17: 関数型志向Python - LLまつり2013
Page 18: 関数型志向Python - LLまつり2013
Page 19: 関数型志向Python - LLまつり2013

(eq? functional

X_language)

Page 20: 関数型志向Python - LLまつり2013

ERROR:Unbound valiable:

functional

Page 21: 関数型志向Python - LLまつり2013

type 関数型言語 =

Maybe BuzzWord

Page 22: 関数型志向Python - LLまつり2013

ここまで前置き

Page 23: 関数型志向Python - LLまつり2013

なぜ関数型「指向」としたか

●ここでは「関数型言語」の正確な定義については考えない(定義的には透明参照性があり、そのことによって副作用を封じ込める云々があるが、そこまで厳密に考えると Maybe Me = 死ぬ | 殺される)

Page 24: 関数型志向Python - LLまつり2013

正直、OCaml Meeting Proof Summitが同日で助かった

Page 25: 関数型志向Python - LLまつり2013

なぜ関数型「指向」としたか

●そこで、あえて「関数型言語」とは別に「プログラムの書き方」として「関数型指向」を使う→「関数型指向」と定義するものは、「関数を連鎖させることによって、手続き=プロセスを記述する」に着目をすることとする。→数学的な意味での「関数」の意味と、Pascal以降の「プログラム」的な意味での「関数」を分離する

Page 26: 関数型志向Python - LLまつり2013

Pythonでの例

from __future__ import print_function

one = lambda: 1two = lambda: 2to_list = lambda *fs: [f() for f in fs]do = lambda *args: args[0](*args[1:])

do(print, do(sum, do(to_list, one, two)))

Page 27: 関数型志向Python - LLまつり2013

素直に書くと……

one = 1two = 2test_data = [one, two]result_sum = sum(test_data)print result_sum

Page 28: 関数型志向Python - LLまつり2013

ところで皆さんに質問があります

Page 29: 関数型志向Python - LLまつり2013

「代入」って簡単ですか?

Page 30: 関数型志向Python - LLまつり2013

よくある代入の説明

変数は「箱」です。代入は、変数という「箱」に

値を保管するということです。

Page 31: 関数型志向Python - LLまつり2013

よくある代入の説明

変数は「箱」です。代入は、変数という「箱」に

値を保管するということです。

どういうことだ?

Page 32: 関数型志向Python - LLまつり2013

抜き打ちテスト

Page 33: 関数型志向Python - LLまつり2013

def test(origin_list): result = origin_list result[0] = "FooBar" return result

a = [1, 2, 3]

# リストの最初を# Foobarにするprint test(a)

# [1, 2, 3]を出したいprint a

Page 34: 関数型志向Python - LLまつり2013

[“Foobar”, 2, 3][“Foobar”, 2, 3]

結果

Page 35: 関数型志向Python - LLまつり2013

代入の難しさ

● 値渡しと参照渡しがある● 「何が値渡し」か「何が参照渡し」かは、言語の仕様によって変化する

Page 36: 関数型志向Python - LLまつり2013

真夏の怪談

Page 37: 関数型志向Python - LLまつり2013

「代入の恐怖」

Page 38: 関数型志向Python - LLまつり2013

あれは某プロジェクトの

ことでした

Page 39: 関数型志向Python - LLまつり2013

プロジェクトはPHPで

書かれていたんですよ……

Page 40: 関数型志向Python - LLまつり2013

フレームワークはCakePHP

Page 41: 関数型志向Python - LLまつり2013

コントローラを開いたら……

Page 42: 関数型志向Python - LLまつり2013

メソッド2500行

Page 43: 関数型志向Python - LLまつり2013

あなたの隣にも、ほら……

Page 44: 関数型志向Python - LLまつり2013

代入の難しさ

● 代入は「データ」をとりあえずおいておく場所として機能する

● そうすると、代入しまくってなんとかしようとする

● 何も考えないとメソッドや関数が肥大化する

Page 45: 関数型志向Python - LLまつり2013

代入の難しさ

Page 46: 関数型志向Python - LLまつり2013

「Object Calisthenics」

インスタンス変数は二つまで

Page 47: 関数型志向Python - LLまつり2013

「関数」を意識する

●細かく「関数」(or メソッド)にすることで、その操作が何を目的にしているのかというのを意識的に命名できる

Page 48: 関数型志向Python - LLまつり2013

例:Fizzbuzz

ルール● 1..100の数が入力される● 3で割り切れる数は”Fizz”● 5で割り切れる数は”Buzz”● 3と5で割り切れる数は”FizzBuzz”● 上記に当てはまらない場合、数を返す

Page 49: 関数型志向Python - LLまつり2013

素直に書くと……

def fizzbuzz(x): if x % 15 == 0: return "FizzBuzz" if x % 3 == 0: return "Fizz" if x % 5 == 0: return "Buzz" return x

for x in range(1, 100): print fizzbuzz(x)

Page 50: 関数型志向Python - LLまつり2013

ここで問題です

Page 51: 関数型志向Python - LLまつり2013

問題: lambda_fizzbuzz

from __future__ import print_function

def function_fizzbuzz(x): #fizzとbuzzの関数を定義すること #ただし、lambdaだけで定義せよ

return fizz(buzz(x))

[print(function_fizzbuzz(x)) for x in range(1, 100)]

Page 52: 関数型志向Python - LLまつり2013

lambdaとは

Page 53: 関数型志向Python - LLまつり2013

Pythonにおけるlambda

origin = lambda x: x# <function __main__.<lambda>>

def _lambda(x): return x

custom = _lambda

#要するにfunction objectを渡している# >>> (lambda x: x * 2)(3) # 6

Page 54: 関数型志向Python - LLまつり2013

考え方

● 出力結果の可能性は、入力された数, “Fizz”, “Buzz”, “FizzBuzz”

● 結果は「数」か「文字」● 「文字」の場合は、3で割り切れる、5で割り切れ

る、15で割り切れるときに出力する● 15で割り切れる = 3で割り切れ、かつ5で割り切れる● 3, 5 をフラグで管理し、3で割り切れるときは”Fizz”、5で割り切れるときは”Buzz”に置換し、両方に当てはまる場合は、二つをあわせる。

Page 55: 関数型志向Python - LLまつり2013

条件演算子を使おう

_buzz = lambda x: “” if x % 3 else “Buzz”

# ある値の後に “if” が入ると、# あいだの値がFalseだと、else以降の値が# 採用される

# ちなみに、Pythonは 0, “”, [], () を 判定すると# False が返ってくるので、割り切れるときは# False になると理解する

Page 56: 関数型志向Python - LLまつり2013

条件演算子を使おう

_fizz = lambda x: “” if x % 3 else “FIzz”_buzz = lambda x: “” if x % 5 else “Buzz”

# 同じような式を省略できないのか

Page 57: 関数型志向Python - LLまつり2013

クロージャと和解せよ

Page 58: 関数型志向Python - LLまつり2013

クロージャを使おう

変数のスコープはソースコード内の位置に

よって決定され入れ子にされた関数は

外側のスコープで宣言された変数にアクセスする

https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Closures

Page 59: 関数型志向Python - LLまつり2013

外側にスコープがある変数?

Page 60: 関数型志向Python - LLまつり2013

クロージャを使おう

def closure(x): def _function(): return x return _function

one = closure(1)print one()

lambda_closure = lambda x: lambda: xtwo = lambda_closure(2)print two()

Page 61: 関数型志向Python - LLまつり2013

クロージャを使おう

ポイント●関数内部で定義された関数は、その関数を定義しようとしている関数に渡された引数を参照できる

Page 62: 関数型志向Python - LLまつり2013

クロージャを使おう

ポイント●関数内部で定義された関数は、その関数を定義しようとしている関数に渡された引数を参照できる

お前は何を言っている

Page 63: 関数型志向Python - LLまつり2013

想像してごらん……

クロージャ関数は「箱」である

Page 64: 関数型志向Python - LLまつり2013

想像してごらん……

クロージャ関数「xって値を

この関数に入れておきましたので、呼び出せば取り出せますよ」

Page 65: 関数型志向Python - LLまつり2013

あれ、この説明どこかで……

Page 66: 関数型志向Python - LLまつり2013

よくある代入の説明

変数は「箱」です。代入は、変数という「箱」に

値を保管するということです。

Page 67: 関数型志向Python - LLまつり2013

よくあるクロージャ関数の説明

クロージャ関数は「箱」です。クロージャ関数は、関数という「箱」に

値を保管するということです。

Page 68: 関数型志向Python - LLまつり2013

抜き打ちテスト

Page 69: 関数型志向Python - LLまつり2013

closure = lambda x: lambda: xfoo = closure([1, 2, 3])

print foo()foo()[0] = "Foobar"print foo()

Page 70: 関数型志向Python - LLまつり2013

あ、ここ代入でやったところだ!(by. 受験生)

Page 71: 関数型志向Python - LLまつり2013

[1, 2, 3][“Foobar”, 2, 3]

結果

Page 72: 関数型志向Python - LLまつり2013

「代入」は何度でも蘇る

Page 73: 関数型志向Python - LLまつり2013

変数が死んでも第二、

第三の代入が現れるだろう

Page 74: 関数型志向Python - LLまつり2013

「関数」を渡していると

いって油断するな

Page 75: 関数型志向Python - LLまつり2013

deepcopyと和解せよ

Page 76: 関数型志向Python - LLまつり2013

from copy import deepcopy closure = lambda x: lambda: deepcopy(x)array = closure([1, 2, 3])array()[0] = "Foobar"

print array()

Page 77: 関数型志向Python - LLまつり2013

[1, 2, 3]

結果

Page 78: 関数型志向Python - LLまつり2013

deepcopyと和解せよ

ポイント●深いコピー(deep copy)は新たな複合オブジェクトを作成し、その後元のオブジェクト中に見つかったオブジェクトのコピーを挿入します。

http://docs.python.jp/2/library/copy.html?highlight=deepcopy

Page 79: 関数型志向Python - LLまつり2013

「似非原さん」

Page 80: 関数型志向Python - LLまつり2013

「先ほどから色々と

説明していますが」

Page 81: 関数型志向Python - LLまつり2013

「lambdafizzbuzz

進捗どうですか」

Page 82: 関数型志向Python - LLまつり2013

ウッ

Page 83: 関数型志向Python - LLまつり2013

問題: lambda_fizzbuzz

from __future__ import print_function

def function_fizzbuzz(x): #fizzとbuzzの関数を定義すること #ただし、lambdaだけで定義せよ

return fizz(buzz(x))

[print(function_fizzbuzz(x)) for x in range(1, 100)]

Page 84: 関数型志向Python - LLまつり2013

解答: lambda_fizzbuzzfrom __future__ import print_function

_div_to_str = lambda x, y: lambda _x: "" if _x % x else y

_buzz = _div_to_str(5, "Buzz")buzz = lambda x: [_buzz(x), x]

__fizz = _div_to_str(3, "Fizz")_fizz = lambda x: [__fizz(x[1]) + x[0], x[1]]fizz = lambda x: print(_fizz(x)[0]) if (_fizz(x)[0]) else print(x[1])

fizzbuzz = lambda x: fizz(buzz(x))

[fizzbuzz(x) for x in range(1, 100)]

Page 85: 関数型志向Python - LLまつり2013

これがlambdaの力である

Page 86: 関数型志向Python - LLまつり2013

関数型指向Python

LLまつり2013 / @esehara

Page 87: 関数型志向Python - LLまつり2013

関数型指向Python

LLまつり2013 / @esehara改め

Page 88: 関数型志向Python - LLまつり2013

Lambda型指向Python

LLまつり2013 / @esehara

Page 89: 関数型志向Python - LLまつり2013

Page 90: 関数型志向Python - LLまつり2013

「似非原さん」

Page 91: 関数型志向Python - LLまつり2013

「先ほどから色々と

説明していますが」

Page 92: 関数型志向Python - LLまつり2013

「プレゼンの納期(20分)どうですか」

Page 93: 関数型志向Python - LLまつり2013

ウッ

Page 94: 関数型志向Python - LLまつり2013

課題

Page 95: 関数型志向Python - LLまつり2013

decoratorと和解せよ

Page 96: 関数型志向Python - LLまつり2013

問題: decorator_fizzbuzz

from __future__ import print_function

@fizz@buzzdef decorator_fizzbuzz(x): pass

[print(decorator_fizzbuzz(x)) for x in range(1, 100)]

Page 97: 関数型志向Python - LLまつり2013

Pythonにおけるdecorator

PEP 318Decorators for

Functions and Methods

Page 98: 関数型志向Python - LLまつり2013

Pythonにおけるdecorator

@dec2@dec1def func(arg1, arg2, ...): pass

def func(arg1, arg2, ...): passfunc = dec2(dec1(func))

Page 99: 関数型志向Python - LLまつり2013

例: lambda_fizzbuzz

fizzbuzz = lambda x: fizz(buzz(x))

Page 100: 関数型志向Python - LLまつり2013

例: decorator_fizzbuzz

decorator_fizzbuzz = fizz(buzz(func))

Page 101: 関数型志向Python - LLまつり2013

ご静聴ありがとうございました

Page 102: 関数型志向Python - LLまつり2013

PyConの成功心からお祈り

しています