Skip to content

Instantly share code, notes, and snippets.

@tonosaman
Created October 21, 2015 08:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tonosaman/e6a2ab98ae747cc86b6e to your computer and use it in GitHub Desktop.
Save tonosaman/e6a2ab98ae747cc86b6e to your computer and use it in GitHub Desktop.

(Ruby)Procオブジェクト: メソッドを第一級オブジェクトとして扱う

  • Procオブジェクトの作り方いろいろ

    > def hoge(a, b); a + b;  end
    > p = method(:hoge).to_proc
    > p = Proc.new { |a, b| a + b } 
    > p = lambda { |a, b| a + b }
    > p = proc { |a, b| a + b }
    > p = ->(a, b) { a + b }
    
    > p.call(1, 2) #=> 3
    > p.(1,2) #=> 3
  • yield, & + call: レシーバーがブロックを第一級オブジェクトとして受け取る(Ruby)

    > def f(x); yield(x) + 1; end
    > def f(x, &g); g.call(x) + 1; end
    > def f(x, &g); g.(x) + 1; end
    
    > f(2) { |n| n * n } #=>5
  • Symbol#to_proc: シンボルと同名のメソッドをレシーバに呼び出してもらうためのProcオブジェクトを作る

    > :to_s.to_proc #=> proc {|x| x.to_proc }
    • シンボルと同名のメソッドが存在していることが前提のダックタイピング。
    • レシーバの扱う型が同名のメソッドを有していることを担保する必要がある。
  • Procオブジェクトのcurry化

    > f = proc {|a, b| a + b}.curry #=> proc {|a| proc {|b| a + b}}
    > f.(1).(2)
    => 3
    • 部分適用したProcオブジェクトを、高階関数で使用するなど
  • Procオブジェクトと高階関数

    > (1..3).map(&Proc.new { |n| n.to_s }) #=> ["1", "2", "3"]
    > (1..3).map(&lambda { |n| n.to_s }) #=> ["1", "2", "3"]
    > (1..3).map(&proc { |n| n.to_s }) #=> ["1", "2", "3"]
    > (1..3).map(&->n{ n.to_s }) #=> ["1", "2", "3"]
    > (1..3).map(&:to_s.to_proc) #=> ["1", "2", "3"]
    > (1..3).map(&:to_s) #=> ["1", "2", "3"]
  • ここまでくれば関数が第一級オブジェクトである言語の表記に近い(F#,Haskell)

    > [1..3] |> List.map (fun x -> x.ToString());;
    val it : string list = ["1"; "2"; "3"]
    > map show [1..3]
    ["1","2","3"]
    > import Control.Applicative ((<$>))
    > show <$> [1..3]
    ["1","2","3"]
  • 関数結合は怒られそうなのでやめとく

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment