Object#method はメソッドをオブジェクト化するものである。
Method は取り出しの対象であるメソッドがなければ作れませんが、Proc は準備なしに作れます。その点から Proc は使い捨てに向き、Method は何度も繰り返し生成する場合に向くと言えます。また内包するコードの大きさという点では Proc は小規模、Method は大規模コードに向くと言えます。
https://docs.ruby-lang.org/ja/latest/class/Method.html
例として、ここのダイクストラ法のメソッドを使ってみる。まず、Hash で全体のグラフ構造を与える。
graph = {s: {t: 6, y: 4}, t: {x: 3, y: 2}, x: {z: 4}, y: {z: 3, t: 1, x: 9}, z: {s: 7, x: 5}}
このグラフに対して、始点を与えてダイクストラ法を実行する関数を、Method オブジェクトから作ってみる。
dijkstra = method(:dijkstra).curry
give_shortest = dijkstra.(graph)
これで、例えば始点:s
、:x
を与えて最短経路が求められる。
give_shortest.(:s).first #=>{:s=>0, :t=>5, :y=>4, :z=>7, :x=>8} give_shortest.(:x).first #=>{:x=>0, :z=>4, :s=>11, :t=>16, :y=>15}
例えば:s
を始点としたとき、:x
までの最短距離は8であるとわかる。同様に、:x
を始点としたとき、:s
までの最短距離は11である。
次いで、始点と終点を与え、最短距離と最短経路を出力する関数を作ってみる。
calc_path = ->(dijkstra_func, start, goal) { shortest, pred = dijkstra_func.(start) route = [goal] route.unshift(pred[route[0]]) until route[0] == start [shortest[goal], route] }.curry shortest_path = calc_path.(give_shortest)
こんな風に使える。
shortest_path.(:s, :x) #=>[8, [:s, :y, :t, :x]] shortest_path.(:x, :s) #=>[11, [:x, :z, :s]]
つまり、始点が:s
で終点が:x
のとき、最短経路は8で、その経路は s→y→t→x の順であるとわかる。
このように、Method オブジェクトがカリー化されたgive_shortest
が、何度も使い回されていることがわかると思う。これを変えれば、同じコードで別のグラフにも簡単に対応できる。