【一人 bugs.ruby Advent Calendar 2021】[Feature #17576] Partial Functions (procs, lambdas)【2日目】

【一人 bugs.ruby Advent Calendar 2021】[Feature #17576] Partial Functions (procs, lambdas)【2日目】

一人 bugs.ruby Advent Calendar 2021 2日目の記事になります。
今回はブロック構文に in を使ったガード節を追加する提案です。

[Feature #17576] Partial Functions (procs, lambdas)

ブロック構文に in を使ったガード節を追加する提案です。
以下のように in を使ってガード節がかけるようになります。

partial_proc = proc do |arg|
# ここの `in x if x.odd?` の部分がガード節の条件になります。  
in x if x.odd?
  "#{x} is odd"
end

このような Proc オブジェクトに対して以下のように Proc#defined?Proc#call_or_else を使えるようにする感じらしい。

# `defined?` で引数が有効かどうかを判定する
partial_proc.defined?(42) #=> false
partial_proc.defined?(41) #=> true

# call で実際に呼び出す
# 該当するガード節がない場合は例外が発生する
partial_proc.call(42) #=> raises NoMatchingPatternError (42)
partial_proc.call(41) #=> 41 is odd

# call_or_else で見つからなかった場合の挙動をブロックに記述する
partial_proc.call_or_else(42) { "fallback value" } #=> 'fallback value'
partial_proc.call_or_else(41) { "fallback value" } #=> 41 is odd

これを用いて FizzBuzz を書くと多分以下のような感じですかね?

p (1..20).map do |n|
in Integer if n % 15 == 0
  "fizzbuzz"
in Integer if n % 3 == 0
  "fizz"
in Integer if n % 5 == 0
  "buzz"
in Integer
  n
end

最初のコードを見たときは『どういうこっちゃ?』と思ったけどガード節と見れば納得した。
ただ、ガード節自体は便利だけど defined?call_or_else は微妙なのでこれは別に議論すべきじゃないかなーと思わなくもない。
関係ないけど以下みたいなガード節書きたいよね?

class C
  def foo(*args)
    # 引数とパターンマッチして該当する処理を呼び出す
    in [Integer]; foo_int_body(a, nil)
    in [a];       foo_body(a, nil)
    in [a, b];    foo_body(a, b)
  end
end