櫓日誌

<< RSpecの拡張 | main | 続:Rubyで内包表現 >>
スポンサーサイト

一定期間更新がないため広告を表示しています

| スポンサードリンク | - | | - | - |
Rubyで内包表現

Haskellの内包表現を知ってRubyでも使いたくなった。試しに実装。

require 'active_support/binding_of_caller'

class Naiho
  attr_reader :element, :bind, :range
  def initialize(element, bind, range)
    @element = element
    @bind = bind
    @range = range
  end
  
  def to_list(restrictions, binding)
    eval(<<-NAIHO, binding)
      #@range.select {|#@bind|  #{restrictions.join('&&')} }.map do |#@bind|
        #@element
      end
    NAIHO
  end
end

class String
  def |(other)
    raise  unless other =~ /^(.+)<-(.+)$/
    Naiho.new(self, $1, $2)
  end
end

$n = Object.new
def $n.[](naiho, *restrictions)
  raise  unless  naiho.instance_of?(Naiho)
  Binding.of_caller do |binding|
    naiho.to_list(restrictions, binding)
  end
end


=begin
class Array
  def initialize(args)
    if args.first.instance_of?(Naiho)
      naiho, *restrictions = args
      Binding.of_caller do |binding|
        naiho.to_list(restrictions, binding)
      end
    else
      super
    end
  end
end
=end
例1:
xs = [10,20,3,-5,1,10,100]
$n['x*2' | 'x <- xs', 'x <= 10']
=> [20, 6, -10, 2, 20]
例2:
def quicksort(x = nil, *xs)
  return []  if x == nil
  quicksort(*$n['y' | 'y <- xs', 'y < x']) + [x] + quicksort(*$n['y' | 'y <- xs', 'y >= x'])
end
quicksort(*xs)
=> [-5, 1, 3, 10, 10, 20, 100]

ほんとは、Arrayのinitializeを上書きできれば以下の式で済むんだけど、配列式の場合は Arrayのinitializeが呼ばれないみたいだ。set_trace_funcにすら反応しなかった。

['x*2' | 'x <- xs', 'x <= 10']

この実装のために、caller bindingが取得できなくて困っていたところに、るびまのRailsの記事でRailsはset_trace_funcで実現していることを知った。というわけで、躊躇なくbinding_of_callerを利用。スレッドセーフではなくなりそうだけど、その辺は継続を使うことでどうにかしてるのかな。そのうち見てみよう。

それにしてもメタプログラミングは楽しいや。

| YAGURA | ソフトウェア | 22:24 | comments(0) | trackbacks(1) |
スポンサーサイト
| スポンサードリンク | - | 22:24 | - | - |









http://yaglog.jugem.jp/trackback/35
鞳纃蒹 矼頤鈞邇竡 體籥 闔 袱驫
鞳纃蒹 矼頤鈞邇竡 體籥 闔 袱驫
| 鞳纃蒹 矼頤鈞邇竡 體籥 闔 袱驫 | 2010/06/30 1:08 PM |
  12345
6789101112
13141516171819
20212223242526
2728293031  
<< August 2017 >>

このページの先頭へ