Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
22
Help us understand the problem. What is going on with this article?
@kasei-san

Proc#curry について

More than 5 years have passed since last update.

カリー化ってなに?

複数の引数をとる関数を、引数が「もとの関数の最初の引数」で戻り値が「もとの関数の残りの引数を取り結果を返す関数」であるような関数にすること

カリー化 - Wikipedia

サンプル(Javascript)

var func = function(x, y) { return x * y; }
var curried = function(x) { 
  return function(y) {
    return func(x, y);
  }
}

curried(2)(3); // 6

部分適用とカリー化の違い

カリー化は部分適用と混同されやすい。部分適用とは、複数引数ある関数の引数の一部だけに実引数を適用する操作のこと
一方、カリー化は、引数への値の適用までは行わない

カリー化 - Wikipedia

サンプル(Javascript)

var func = function(x, y) { return x * y; }

// 部分適用の為の関数(curried)を作る所までがカリー化
var curried = function(x) { 
  return function(y) {
    return func(x, y);
  }
}

// カリー化された関数を使って、部分適用された関数(partialized)を作る
var partialized = curried(2);
partialized(3); // 6

Ruby でカリー化

pr = -> x, y { x * y }          # Proc.new のシンタックスシュガー
puts pr.(2,3)                   # -> 6 : .() は、Proc#call のシンタックスシュガー

# Proc インスタンスのカリー化
pr_crrried = pr.curry          

# Proc インスタンスの部分適用
pr_partialized = pr_crrried.(2) 

puts pr_partialized.(3)         # -> 6

カリー化すると何が得なの?

複数の引数を持つ関数に予め引数を渡しておける

複数の引数を持つ関数をmapしたい場合

pr = -> x, y { x * y }
p [1, 2, 3].map {|x| pr.(x, 3) } # -> [3, 6, 9]

Proc#curry を使うとブロックを使わなくて良くなる

pr = -> x, y { x * y }
[1,2,3].map(&pr.curry.(3)) # -> [3, 6, 9]

似たような関数を複数用意すること無く、部分適用を使って動的に生成できる

たとえば、FuzzBuzz
Proc#=== は、Proc#call と同じなので、case文のwhen式は、caseに渡した式を引数とするProcを渡す事ができる

fuzzbuzz = -> n {
  case n
  when -> n { (n % 15).zero? } then 'fuzzbuzz'
  when -> n { (n % 3).zero? }  then 'fuzz'
  when -> n { (n % 5).zero? }  then 'buzz'
  else
    n
  end
}

p (1..100).to_a.map(&fuzzbuzz) # -> [1, 2, "fuzz", 4, "buzz", "fuzz" ...

when文に渡しているProcは部分適用を使えば、こんな風に書ける

fuzzbuzz = -> n {
  curried = Proc.new {|base, n| (n % base).zero? }.curry
  case n
  when curried.(15) then 'fuzzbuzz'
  when curried.(3)  then 'fuzz'
  when curried.(5)  then 'buzz'
  else
    n
  end
}
p (1..100).to_a.map(&fuzzbuzz) # -> [1, 2, "fuzz", 4, "buzz", "fuzz" ...

参考

22
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
kasei-san
小林の中の人 長文はblogに。QiitaにはちょっとしたTIPSを
lclco
業界最大手高速バス料金比較サイト「バス比較なび」やLCCなど飛行機との比較ができる「格安移動」を運営

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
22
Help us understand the problem. What is going on with this article?