Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

11,471 views

Published on

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

  1. 1. 関数型指向 Python LLまつり2013 / @esehara
  2. 2. お前 誰だ
  3. 3. Esehara Shigeo(29) 言語:Python OS:Ubuntu + Amesome(タイル型) 好きなMonad: Maybe 気になる言語: Prolog 所属: 株式会社マリーチ
  4. 4. このスライドは以下に、 既にアップされているので スライドを手元でみたいときは http://www.slideshare.net/esehara/ から見てください
  5. 5. ところで 皆さんに 質問が あります
  6. 6. 関数型言語 使って ますか?
  7. 7. そもそも 「関数型言語」 ってなんですか?
  8. 8. (eq? functional lisp) => #t / #f ?
  9. 9. (eq? functional lisp)
  10. 10. 『計算機プログラムの構造と解釈』 特徴のもっとも著しいのは プロセスの手続き (procedures) というLispによる記述自体が Lispデータとして表現, 処理出 来ることである. (p. 2)
  11. 11. プロセスの手続き というLispによる 記述……?
  12. 12. 手続きって 関数型 と違うものなの?
  13. 13. 抜き打ち調査
  14. 14. (eq? functional X_language)
  15. 15. ERROR: Unbound valiable: functional
  16. 16. type 関数型言語 = Maybe BuzzWord
  17. 17. ここまで 前置き
  18. 18. なぜ関数型「指向」としたか ●ここでは「関数型言語」の正 確な定義については考えな い (定義的には透明参照性があり、その ことによって副作用を封じ込める云々 があるが、そこまで厳密に考えると Maybe Me = 死ぬ | 殺される)
  19. 19. 正直、 OCaml Meeting Proof Summitが 同日で助かった
  20. 20. なぜ関数型「指向」としたか ●そこで、あえて「関数型言語」とは別に 「プログラムの書き方」として「関数型 指向」を使う →「関数型指向」と定義するものは、「関数を連鎖さ せることによって、手続き=プロセスを記述する」に 着目をすることとする。 →数学的な意味での「関数」の意味と、Pascal以降 の「プログラム」的な意味での「関数」を分離する
  21. 21. Pythonでの例 from __future__ import print_function one = lambda: 1 two = lambda: 2 to_list = lambda *fs: [f() for f in fs] do = lambda *args: args[0](*args[1:]) do(print, do(sum, do(to_list, one, two)))
  22. 22. 素直に書くと…… one = 1 two = 2 test_data = [one, two] result_sum = sum(test_data) print result_sum
  23. 23. ところで 皆さんに 質問が あります
  24. 24. 「代入」って 簡単ですか?
  25. 25. よくある代入の説明 変数は「箱」です。 代入は、変数という「箱」に 値を保管するということです。
  26. 26. よくある代入の説明 変数は「箱」です。 代入は、変数という「箱」に 値を保管するということです。 どういう ことだ?
  27. 27. 抜き打ちテスト
  28. 28. 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
  29. 29. [“Foobar”, 2, 3] [“Foobar”, 2, 3] 結果
  30. 30. 代入の難しさ ● 値渡しと参照渡しがある ● 「何が値渡し」か「何が参照 渡し」かは、言語の仕様に よって変化する
  31. 31. 真夏の怪談
  32. 32. 「代入の恐怖」
  33. 33. あれは 某プロジェクトの ことでした
  34. 34. プロジェクトは PHPで 書かれて いたんですよ……
  35. 35. フレームワークは CakePHP
  36. 36. コントローラを 開いたら……
  37. 37. メソッド 2500行
  38. 38. あなたの隣にも、ほら……
  39. 39. 代入の難しさ ● 代入は「データ」をとりあえずおいておく 場所として機能する ● そうすると、代入しまくってなんとかしよ うとする ● 何も考えないとメソッドや関数が肥大化 する
  40. 40. 代入の難しさ
  41. 41. 「Object Calisthenics」 インスタンス 変数は二つまで
  42. 42. 「関数」を意識する ● 細かく「関数」(or メソッド)に することで、その操作が何を 目的にしているのかというの を意識的に命名できる
  43. 43. 例:Fizzbuzz ルール ● 1..100の数が入力される ● 3で割り切れる数は”Fizz” ● 5で割り切れる数は”Buzz” ● 3と5で割り切れる数は”FizzBuzz” ● 上記に当てはまらない場合、数を返す
  44. 44. 素直に書くと…… 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)
  45. 45. ここで 問題です
  46. 46. 問題: 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)]
  47. 47. lambda とは
  48. 48. Pythonにおけるlambda origin = lambda x: x # <function __main__.<lambda>> def _lambda(x): return x custom = _lambda #要するにfunction objectを渡している # >>> (lambda x: x * 2)(3) # 6
  49. 49. 考え方 ● 出力結果の可能性は、入力された数, “Fizz”, “Buzz”, “FizzBuzz” ● 結果は「数」か「文字」 ● 「文字」の場合は、3で割り切れる、5で割り切れ る、15で割り切れるときに出力する ● 15で割り切れる = 3で割り切れ、かつ5で割り切れる ● 3, 5 をフラグで管理し、3で割り切れるときは”Fizz”、 5で割り切れるときは”Buzz”に置換し、両方に当ては まる場合は、二つをあわせる。
  50. 50. 条件演算子を使おう _buzz = lambda x: “” if x % 3 else “Buzz” # ある値の後に “if” が入ると、 # あいだの値がFalseだと、else以降の値が # 採用される # ちなみに、Pythonは 0, “”, [], () を 判定すると # False が返ってくるので、割り切れるときは # False になると理解する
  51. 51. 条件演算子を使おう _fizz = lambda x: “” if x % 3 else “FIzz” _buzz = lambda x: “” if x % 5 else “Buzz” # 同じような式を省略できないのか
  52. 52. クロージャと 和解せよ
  53. 53. クロージャを使おう 変数のスコープは ソースコード内の位置に よって決定され 入れ子にされた関数は 外側のスコープで宣言された 変数にアクセスする https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Closures
  54. 54. 外側に スコープが ある変数?
  55. 55. クロージャを使おう def closure(x): def _function(): return x return _function one = closure(1) print one() lambda_closure = lambda x: lambda: x two = lambda_closure(2) print two()
  56. 56. クロージャを使おう ポイント ●関数内部で定義された関 数は、その関数を定義しよ うとしている関数に渡され た引数を参照できる
  57. 57. クロージャを使おう ポイント ●関数内部で定義された関 数は、その関数を定義しよ うとしている関数に渡され た引数を参照できる お前は 何を 言っている
  58. 58. 想像してごらん…… クロージャ関数は 「箱」である
  59. 59. 想像してごらん…… クロージャ関数 「xって値を この関数に入れておき ましたので、呼び出せ ば取り出せますよ」
  60. 60. あれ、この説明 どこかで……
  61. 61. よくある代入の説明 変数は「箱」です。 代入は、変数という「箱」に 値を保管するということです。
  62. 62. よくあるクロージャ関数の説明 クロージャ関数は「箱」です。 クロージャ関数は、 関数という「箱」に 値を保管するということです。
  63. 63. 抜き打ちテスト
  64. 64. closure = lambda x: lambda: x foo = closure([1, 2, 3]) print foo() foo()[0] = "Foobar" print foo()
  65. 65. あ、ここ代入で やったところだ! (by. 受験生)
  66. 66. [1, 2, 3] [“Foobar”, 2, 3] 結果
  67. 67. 「代入」は 何度でも 蘇る
  68. 68. 変数が死んでも 第二、 第三の代入 が現れるだろう
  69. 69. 「関数」を 渡していると いって 油断するな
  70. 70. deepcopy と和解せよ
  71. 71. from copy import deepcopy closure = lambda x: lambda: deepcopy(x) array = closure([1, 2, 3]) array()[0] = "Foobar" print array()
  72. 72. [1, 2, 3] 結果
  73. 73. deepcopyと和解せよ ポイント ●深いコピー(deep copy)は新たな複 合オブジェクトを作成し、その後元の オブジェクト中に見つかったオブジェ クトのコピーを挿入します。 http://docs.python.jp/2/library/copy.html?highlight=deepcopy
  74. 74. 「似非原さん」
  75. 75. 「先ほどから 色々と 説明して いますが」
  76. 76. 「lambda fizzbuzz 進捗どうですか」
  77. 77. ウッ
  78. 78. 問題: 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)]
  79. 79. 解答: lambda_fizzbuzz from __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)]
  80. 80. これが lambdaの 力である
  81. 81. 関数型指向 Python LLまつり2013 / @esehara
  82. 82. 関数型指向 Python LLまつり2013 / @esehara 改め
  83. 83. Lambda型 指向Python LLまつり2013 / @esehara
  84. 84.
  85. 85. 「似非原さん」
  86. 86. 「先ほどから 色々と 説明して いますが」
  87. 87. 「プレゼンの 納期(20分) どうですか」
  88. 88. ウッ
  89. 89. 課題
  90. 90. decorator と和解せよ
  91. 91. 問題: decorator_fizzbuzz from __future__ import print_function @fizz @buzz def decorator_fizzbuzz(x): pass [print(decorator_fizzbuzz(x)) for x in range(1, 100)]
  92. 92. Pythonにおけるdecorator PEP 318 Decorators for Functions and Methods
  93. 93. Pythonにおけるdecorator @dec2 @dec1 def func(arg1, arg2, ...): pass def func(arg1, arg2, ...): pass func = dec2(dec1(func))
  94. 94. 例: lambda_fizzbuzz fizzbuzz = lambda x: fizz(buzz(x))
  95. 95. 例: decorator_fizzbuzz decorator_fizzbuzz = fizz(buzz(func))
  96. 96. ご静聴 ありがとう ございました
  97. 97. PyConの成功 心からお祈り しています

×