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.

RubyとJavaScriptに見る第一級関数

4,716 views

Published on

Ruby(Rails)や JavaScript を使うWeb系を想定して、あまり語られることの無い概念的な話を交えて包括的に関数を説明してみた。

Published in: Technology
  • Be the first to comment

RubyとJavaScriptに見る第一級関数

  1. 1. Ruby と JavaScript に見る第一級関数by Altech 2012/09
  2. 2. 伝えたいこと 関数はデータ!数値とか配列と同じデータ! 変数に代入するのも自然! 関数型言語じゃなくても関数はデータなんです!・・・という見方をすることで、現代のプログラミング言語を包括的に理解できます(別の言語を学びやすくなります)。C言語あるいは Java と同じ枠組みで Ruby や JavaScript を見ると、思考の幅が狭まります(設計が貧弱になります)。文法の差異などの表層と、言語の根本的な表現力といった本質を分離して考えられます(すっきりして気持ちが良いです)。なので、ぜひこういう見方をしましょう!!
  3. 3. Topics関数ではなく手続きと見る第一級のデータ型であるということ色々な言語の第一級のデータ型レキシカルスコープとレキシカルクロージャRuby における様々な手続きの表現方法
  4. 4. Topics関数ではなく手続きと見る第一級のデータ型であるということ色々な言語の第一級のデータ型レキシカルスコープとレキシカルクロージャRuby における様々な手続きの表現方法
  5. 5. そもそも関数(Function)と は よくある関数(function)の概念図 入力に対してなにか計算をして、結果を出力と して返す なんらかの計算を抽象化したもの 1個(以上)の入力と、1個の出力を持つ
  6. 6. 関数では説明できない例「関数(メソッド)の定義は def だよ!」 # DBの最終ログイン時間を更新 def update_user_signin(user_id) user = User.find(user_id) user.update_attribute(“last_signin_at”, Time.now) end 関数と言いつつ、出力がない 関数という概念では説明できない「何か」
  7. 7. 手続き(Procedure)なんかの操作をひとまとめにして抽象化したもの0個以上の入力と、0個以上の出力を持つデータベースへの保存という「手続き」関数という概念を含む、より一般的な概念
  8. 8. まとめ:手続きと関数Ruby や JavaScript (非・純粋関数型言語)では、関数/メソッド/ブロックetc と呼ばれるものは概念的には「手続き」。Procedure。入力を受け取って出力を返す形なら「関数」。最初から概念的な話になってしまいましたが、あとでRuby におけるそれらの扱いを説明するために最初にこの話をしました。以降、JavaScript の説明などでは慣習に従って関数という言葉を手続きの意味で使います。
  9. 9. Topics関数ではなく手続きと見る第一級のデータ型であるということ色々な言語の第一級のデータ型レキシカルスコープとレキシカルクロージャRuby における様々な手続きの表現方法
  10. 10. 第一級のデータ型大体以下のようなことができるデータ型を指す 関数の引数に渡せる 関数の戻り値として返せる 配列など複合データ型の中に埋め込める 変数に格納できるよーするに、普段から数値やら文字列に対して行っている基本的な操作・能力。これから C, Java, Ruby の順にこのデータ型を見ていきます。
  11. 11. C言語におけるデータ型 int(整数) float(実数) char(文字) ポインタ(メモリアドレス)とかそんな感じ。全体的に数値の世界。
  12. 12. Javaにおけるデータ型 int(整数) float(実数) char(文字) Stringオブジェクト(文字列)← new ! その他各種オブジェクト← new !とかそんな感じ。基本データ型とオブジェクトがある世界。関数や手続きを表すオブジェクトは原則は作れない。
  13. 13. オブジェクト Rubyにおけるデータ型Ruby =純粋なオブジェクト指向。全てはオブジェクト! Integerオブジェクト(整数) Floatオブジェクト(実数) Stringオブジェクト(文字列) Procオブジェクト(手続き) ← new ! その他各種オブジェクト※ 手続き = Procedure
  14. 14. Procオブジェクト…?# お馴染み eachメソッドに何が渡っているか調べてみるclass Array def each_with_inspect(&procedure) puts procedure.inspect self.each(&procedure) endend # „&‟については後々説明。見えないと思って。--------------------------------------------------[1,2,3].each_with_stdout do |i| print „,‟+i.to_send# stdout => #<Proc:0x…>,1,2,3 eachメソッドには Proc クラスのインスタンスが 渡っていた! do … end の間が手続きで、i が引数だった。
  15. 15. JavaScriptにおける関数-1関数の扱いについては実はとても素直な言語。// 関数の生成function(n) { return n+1 };// 関数を生成して引数に渡す$.click( function(){ … } )// 関数定義=関数を生成して変数に代入するvar fact = function(n){ return n==1 ? 1 : n * fact(n-1)};// 関数定義の特別な書き方。意味は上と同じ!function fact(n){ return n==1 ? 1 : n * fact(n-1)}
  16. 16. JavaScriptにおける関数-2// 関数を呼び出す = ()演算子を後ろに付けてやるだけfact(5) // => 120// 関数を生成した直後にそれを呼び出すことも(function(n){return n*1})(10) // => 20// 型は?typeof fact; //=> function// 複合データ型(JavaScriptのオブジェクト)の中に埋め込んで自作モジュール作成my_math_module = { calc_fact: fucntion(n){…}, calc_comb: function(n,m){…}, … }
  17. 17. 例えばこんなところで// Ruby. モデルのデフォルト値を生成する手続きを設定(mongoid)。->{}で手続きが書けるのは後で。class User field :wasted_at, type: Time, default: ->{ new_record? ? 2.min.ago : Time.now }end// JavaScript. ブラウザで一定時間後に特定の手続きを起動。setTimeout(function(){ … },1000);実際のところ、Ruby は組み込みクラスが充実していて構文がうまくできている(each do … end)のでこれらを使うだけなら必ずしもこういうことは意識する必要はない。とはいえ、時々こういう見方が必要。特にAPIを設計するとき。一方JSは言語機構や組み込み関数、構文がシンプルなので、見た目にも明らかにガリガリ関数を使っていく傾向。でも・・・ やってることは本質的に同じ。
  18. 18. ここまでのまとめ Ruby や JavaScript を使っているなら、当然のよ うに、関数の引数に手続きを渡したり、複合 データの中に埋め込んだり、ということをやっ てる。 関数・手続きもオブジェクトの一つ、それだ け。残りのお話(おまけ) レキシカルスコープとレキシカルクロージャ Ruby における様々な手続きの表現
  19. 19. Topics関数ではなく手続きと見る第一級のデータ型であるということ色々な言語の第一級のデータ型レキシカルスコープとレキシカルクロージャRuby における様々な手続きの表現方法
  20. 20. レキシカルスコープbegin a=5 [1,2].map do |i| a = 10 i*a end # => [10,20] a # => 5enda # => NameError スコープ(scope):変数の有効な領域 レキシカルスコープ(lexical scope):その変数が現 れた字句(ソースコード)上で、内側のスコープほ ど優先されるような、スコープの定義。 上では三つのスコープが入れ子になっている。
  21. 21. レキシカルクロージャvar scale = 10; now = Time.nowvar times = function(n){ items = Item.where(status: Valid) return n * scale items.each do |item|}; item.update_attribute(times(5); // => 50 :checkd_at, now)scale = 1000; endtimes(5); // => 50 よく「クロージャ(Closure)」と言われるもの。 JavaScript の関数や Ruby の Proc オブジェクトは全てこれ。 手続き定義時に、手続き内で定義されていない変数(上の例 ではscaleとnow)は外側のスコープを使って解決する。 レキシカルスコープ的なのであまり意識することはないかも。 「定義した時の環境を閉じ込めるので閉包(closure)」 「環境」とはその時々の変数名(ラベル)と実体(データ)の対応関係のこと。プログラムはこの環境を伴って実行が進む、と考える。 上の例だと、times を定義するときの環境は { scale : 10 } で、この環境に従って{引数:n, 内容:return n* scale, 外部参照: {scale:10} }といった「関数」が構築される(=環境を関数の中に閉じ込める)。 関数が呼ばれるときは、この外部参照:{scale:10} が使われる。{scale:1000} は使われない。ここが大事。
  22. 22. Topics関数ではなく手続きと見る第一級のデータ型であるということ色々な言語の第一級のデータ型レキシカルスコープとレキシカルクロージャRuby における様々な手続きの表現方法
  23. 23. Rubyにおける手続きの形Procオブジェクト Proc.new で生成されるタイプ(lambda? => false) lambda で生成されるタイプ(lambda? => true)メソッド呼び出しにおけるdo … end ブロックインスタンスやクラスのメソッド
  24. 24. Ruby:ProcオブジェクトRubyにおける手続きのオブジェクト表現(まんま)。p = Proc.new do…end で「手続き」を生成、p.call(arg…) で呼び出し。f = lambda do … end でも生成できる。「関数」を表す。lambda は「関数」的に使われることが想定されているので、中に return 1 と書くとcall時の返り値になる。 の形で中に return を書くと、call時に「呼んだProc.new側の」メソッドをリターンする。lambda do |arg| … end は ->(arg){…} という略記あり.
  25. 25. Ruby:do…endブロック手続きを生成して関数に渡すのはどうしても冗長。JavaScriptの例。$.click(function(){ … }) // function という予約語が長いのは別の話…引数として渡す手続きは一つ、という割り切りによるデザインがブロック。Rubyだとこう書ける。 a.click do…end / a.click{…}ブロックはProcオブジェクトではないが、簡単に変換可能。Procオブジェクトをブロックとして渡すには、&を付けてやればいい p = ->(i){retrun i*2}; [1,2,3].map(&p) # => [2,4,6]ブロックをProcオブジェクトとして受け取るには、定義時の引数に&を付けてやればいい。def each_with_inspect(&procedure) という感じ。通常は引数に書く必要はなく、yieldキーワードで渡されている(はずの)ブロックを呼び出すだけでよい。渡されているかどうかをチェックしたいならblock_given?で。
  26. 26. Ruby:メソッド メソッド:オブジェクトに対する関数(手続 き)呼び出しのこと Ruby では class 内 で def によって定義 。 メソッドはクロージャではない。class People a = 10 def max return a endendPeople.new.max # => NameError
  27. 27. まとめ手続き・関数、スコープという観点から Ruby の手続き表現を整理しました。ブロックにより手続きが簡単にメソッドに渡せます。手続きと関数に対応するオブジェクトがあり、ブロックという形での渡し方があります。Ruby における手続きの扱いは大体こんな感じです
  28. 28. 参考文献「コンピュータプログラミングの概念・技法・モデル」(翔泳社)「初めてのRuby」(O‟Reilly)「プログラミング言語Ruby」(O‟Reilly)「JavaScript 第五版」(O‟Reilly)

×