トップ 最新 追記 RSS feed

継続にっき

2004|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|12|
2006|01|03|05|06|08|09|10|12|
2007|01|02|03|05|07|12|
2008|10|
2009|01|05|12|
2010|04|05|11|
2011|01|09|12|
2012|02|03|05|09|12|
2013|02|03|
2014|05|09|
2015|12|
2017|09|

2012-03-03 (Sat)

))) Ruby向けパターンマッチライブラリ「pattern-match」を作った

先日ポストしたScalaっぽいパターンマッチをRubyで実装するをベースに 一通り機能を揃えてライブラリ化した(pattern-match)。

面白そうなパターンをいくつか例に取ってみると、まず多重代入。

match([0, [1, 2, 3, 4]]) {
  with(_[a, _[b, *c, d]]) { # `Array.(a, Array.(b, *c, d))'と同じ
    p [a, b, c, d] #=> [0, 1, [2, 3], 4]
  }
}

Gaucheのutil.match由来の___、__k。

match([[0, 1], [2, 3]]) {
  with(_[_[a, b], ___]) {
    p [a, b] #=> [[0, 2], [1, 3]]
  }
}

赤黒木のbalance(参考までにScala版実装)。

Node = Struct.new(:left, :key, :right)
class R < Node; end
class B < Node; end

def balance(left, key, right)
  match([left, key, right]) {
    with(_[R.(a, x, b), y, R.(c, z, d)]) { R[B[a, x, b], y, B[c, z, d]] }
    with(_[R.(R.(a, x, b), y, c), z, d]) { R[B[a, x, b], y, B[c, z, d]] }
    with(_[R.(a, x, R.(b, y, c)), z, d]) { R[B[a, x, b], y, B[c, z, d]] }
    with(_[a, x, R.(b, y, R.(c, z, d))]) { R[B[a, x, b], y, B[c, z, d]] }
    with(_[a, x, R.(R.(b, y, c), z, d)]) { R[B[a, x, b], y, B[c, z, d]] }
    with(_) { B[left, key, right] }
  }
end

特殊なパターンとしてDuck Typing的なことも出来るようにしてみた。ただ、実用性があるかというと、どうなんだろう……。

match(10) {
  with(Object.(:to_i => a, :foobar => b)) { :not_match }
  with(Object.(:to_i => a, :to_s.(16) => b)) {
    p [a, b] #=> [10, "a"]
  }
}

ちなみに、ruby-trunk - Feature #4085 : Refinements and nested methodsをサポートする環境であれば、 次のような書き方も出来るようになっている*1。Refinements素晴らしい。

def balance(left, key, right)
  match([left, key, right]) {
    with(_[R[a, x, b], y, R[c, z, d]]) { R[B[a, x, b], y, B[c, z, d]] }
    with(_[R[R[a, x, b], y, c], z, d]) { R[B[a, x, b], y, B[c, z, d]] }
    with(_[R[a, x, R[b, y, c]], z, d]) { R[B[a, x, b], y, B[c, z, d]] }
    with(_[a, x, R[b, y, R[c, z, d]]]) { R[B[a, x, b], y, B[c, z, d]] }
    with(_[a, x, R[R[b, y, c], z, d]]) { R[B[a, x, b], y, B[c, z, d]] }
    with(_) { B[left, key, right] }
  }
end

*1 r29944向けパッチで動作確認済み

本日のツッコミ(全5件) [ツッコミを入れる]

Before...

_ shugo [> 外側で得た変数を内側のwithの引数として渡しても、値の参照ではなく常にvariable pattern相当にな..]

_ k_tsj [なるほど、分かりました。 やはり両方ともmatchのネストが原因のようです。 GitHub上のmasterに..]

_ shugo [ありがとうございました。後で確認してみます]


2004|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|12|
2006|01|03|05|06|08|09|10|12|
2007|01|02|03|05|07|12|
2008|10|
2009|01|05|12|
2010|04|05|11|
2011|01|09|12|
2012|02|03|05|09|12|
2013|02|03|
2014|05|09|
2015|12|
2017|09|
トップ 最新 追記 RSS feed