プロキシオブジェクトの例で関数型プログラミングを理解
お金 | 仕事 | 勉強 | プライベート | 健康 | 心
プログラミング関連のコンテンツ
C言語/C++入門 | Ruby入門 | Python入門 | プログラミング全般
=追記(2010/07/23)
Rubyベストプラクティスのひとり読書。理解が難しかった部分を中心にまとめています。
書籍から引用しすぎと思われたページ、理解したページなどを削除して、当初より公開ページを減らしました。すいません。
読書のまとめ記事は難しいと感じたので、今後はブログで読書のまとめは書かないでおきます。差し障りがあれば現存するページも削除致しますので予めご了承下さい。
=追記ここまで
String#lines
文字列を行の配列を生成するEnumeratorに変換します。
プロキシオブジェクトの実装
p137からのコードを理解するために、コードにコメントを多めに入れてみました。
# Lazy::Promiseの実装、コメント多めでコード説明 # Ruby1.9で動作 module NaiveLazy class Promise < BasicObject def initialize(&computation) @computation = computation end def __result__ if @computation @result = @computation.call @computation = nil end @result # &computationブロックを実行した結果を返す end def inspect if @computation "#<NaiveLazy::Promise computation=#{ @computation.inspect }>" else @result.inspect end end def respond_to?(message) message = message.to_sym [:__result__, :inspect].include?(message) || # __result__メソッドにより返されたオブジェクト@resultがmessageメソッドを持っているか調査 __result__.respond_to? message end def method_missing(*a, &b) # promise.some_function を promise.__result__.some_function と解釈 __result__.__send__(*a, &b) end end end # >>cell.width # => #<Lazy::~ # >>cell.width + 10 #=> cellオブジェクトには+メソッドがないのでmethod_missingでフック # => 114 # { 3 }のブロックが&computationに入る num = NaiveLazy::Promise.new { 3 } # +メソッドがmethod_missingでフックされる。num.+(100) → 3.+(100)と解釈 puts num + 100 puts num # __result__ が 3(Fixnumオブジェクト) を返しtrue puts num.respond_to?(:times) # classメソッドがmethod_missingでフックされる。num.class → 3.class と解釈 puts num.class
Ruby1.9で実行
遅延評価
Rubyのコードブロックは遅延評価
lazy.rb
mapのナイーブな実装例
可変状態を最小限にして副作用を減らす
ステートフルとは以前の状態を保持することをいう。
ステートレスとは以前の状態を保持しないことをいう。
ステートフル arr << elem 破壊的 (可変状態、状態保持)
ステートレス arr + [elem] 非破壊的(不変状態、状態未保持)=> 再帰処理でステートレスなコードになる
往々にしてRubyでは再帰は反復より実行速度が遅くなる。
Rubyのメソッドディスパッチのコストが高いため。
injectメソッドで反復を使ったステートレスなmapを作れる。
p143~p145で以下三種類のmap実装のメソッドによるベンチマークが比較されている。
反復+ステートレスじゃない => 1番速い
再帰+ステートレス => 最も遅い
反復+ステートレス => 2番目に速い
反復+ステートレスは、要素を配列に追加するたびに新しいオブジェクトを作る必要があるために遅い。
副作用を避けるということは、可変状態(破壊的)を完全に避けることとは違う。
オブジェクトを別のオブジェクトに変換するときに副作用を避ける単純な方法は、新しいオブジェクトを作って、元のオブジェクトをイテレートしながら、必要な状態変換を実行して、新しいオブジェクトにその状態を入れること
Array#+ のように、操作のたびに新しいオブジェクトを作ることにより、Rubyでステートレスなコードを書ける
再帰はパフォーマンス犠牲の恐れ
オブジェクトをたくさん作りすぎてもパフォーマンス犠牲の恐れ
モジュールによるコード整理
module_function だとプライベート関数が使えない。
extend self にするとOK。
- - 関連記事 -
- 無名クラスを継承するRubyの動的機能
- method_missing()とsend()でフック(処理を捕捉)
- obj.instance_eval(&block)とblock.call(obj)の違いを確認
- コードブロックを用いたサーバーとクライアントの例
- メソッド名とシグニチャを統一して美しいAPI設計
- mustメソッドで読みやすいテスト