Passing block to Proc#call

I'd like to do something like:

x = lambda do |*args|
  if args.size == 5
    # call another block
    yield *args.map{|x| x.gsub(/es$/, '') }
  end
end

x.call(*%w[cats dogs ones twos threes]) do |*words|
  puts words.last # output: thre
end

But x.call(..) { block } raises LocalJumpError: no block given. I'm
not sure how to pass a block because it seems #call doesn't pass it
on. Sorry if this is a common question, but I'm having a hard time
searching for help because "passing block to lamda call" appears in
every page about the basics of closures.

I see lamda {|&block| ... } is added in ruby 1.9, but I'd like to be
compatible with 1.8 too.

Dear Erwin,

maybe this is what you're looking for:

def cut_off_regexp(an_array)
  return proc { |regexp|
    res=[]
    an_array.each{|entry|
      if entry.length>5 and regexp.match(entry)
        res<<entry.sub(regexp,'')
      else
        res<<entry
      end
    }
    res
   }
end
my_array_of_strings=["goes","does","undoes","a long string"]
p1 =cut_off_regexp(my_array_of_strings)
p 'cut off "es" at the end of long strings'
p p1.call(/es$/)
p 'cut out "es" anywhere in a long string'
p p1.call(/es/)

I constructed this from the help about Proc in

http://www.rubycentral.com/book/tut_containers.html .

Best regards,

Axel

···

--
GMX FreeMail: 1 GB Postfach, 5 E-Mail-Adressen, 10 Free SMS.
Alle Infos und kostenlose Anmeldung: http://www.gmx.net/de/go/freemail

I'd like to do something like:

x = lambda do |*args|
if args.size == 5
   # call another block
   yield *args.map{|x| x.gsub(/es$/, '') }
end
end

x.call(*%w[cats dogs ones twos threes]) do |*words|
puts words.last # output: thre
end

Why do you need x here? Do you need to pass it around? Can you show a bit more of the picture?

But x.call(..) { block } raises LocalJumpError: no block given. I'm
not sure how to pass a block because it seems #call doesn't pass it
on. Sorry if this is a common question, but I'm having a hard time
searching for help because "passing block to lamda call" appears in
every page about the basics of closures.

I see lamda {|&block| ... } is added in ruby 1.9, but I'd like to be
compatible with 1.8 too.

There is no other compatible way than to explicitly pass a lambda / proc as argument in 1.8.x:

irb(main):003:0> f = lambda {|a,b| 5.times { a = b[a] }; a }
=> #<Proc:0x7ff7a1c8@(irb):3>
irb(main):005:0> f[0, lambda {|x| x+1}]
=> 5

Kind regards

  robert

···

On 10.06.2007 08:53, Erwin Abbott wrote:

class Proc
  def bcall(*args,&block)
    self.call(*args.concat([*block]))
  end
end

x_y = lambda {|data,proc| proc.call(data) if data.is_a? String }

x_y.bcall("hello") {|data| puts data.succ }

It's a hack, but it works.

···

On 6/10/07, Erwin Abbott <erwin.abbott@gmail.com> wrote:

I'd like to do something like:

x = lambda do |*args|
  if args.size == 5
    # call another block
    yield *args.map{|x| x.gsub(/es$/, '') }
  end
end

x.call(*%w[cats dogs ones twos threes]) do |*words|
  puts words.last # output: thre
end

But x.call(..) { block } raises LocalJumpError: no block given. I'm
not sure how to pass a block because it seems #call doesn't pass it
on. Sorry if this is a common question, but I'm having a hard time
searching for help because "passing block to lamda call" appears in
every page about the basics of closures.

I see lamda {|&block| ... } is added in ruby 1.9, but I'd like to be
compatible with 1.8 too.

--
Chris Carter
concentrationstudios.com
brynmawrcs.com

x = lambda do |*args|
   if args.size == 5
     # call another block
     yield *args.map{|x| x.gsub(/es$/, '') }
   end
end

You are using 2 variables with the same name (x) in the same
scope. So, in fact, you are only using 1 variable...

gegroet,
Erik V. - http://www.erikveen.dds.nl/

> x.call(*%w[cats dogs ones twos threes]) do |*words|
> puts words.last # output: thre
> end

Why do you need x here? Do you need to pass it around? Can you show a
bit more of the picture?

I ended up refactoring, but earlier I was parsing some text by
associating an array of attributes (like, [/a/, /b/, /c$/] that might
match the first 3 words) with a block that processed the matching
text, and then moved the position in the string forward by 3 words. I
tried wanted to be able to do this like:

match = proc do |*regexs|
  if words[position..position+regexs.size] match given regexs
    parsed << yield *words[ .. ]
  end
end

words = %w[the quick brown egg jumped under the slow zebra]
parsed =

while position < words.size
  match.call(//, /ed/, //) do {|a, b, c| "#{a} #{b.upcase} #{c}" }
  match.call(/the/, //) do {|a, b| "the #{b.upcase}" }

  # increment position somewhere, maybe in match..? this was messy
end

# parsed => [the QUICK brown egg JUMPED under the SLOW zebra]

# where the matched strings were "the quick", "egg jumped under"
# and "the slow"

Anyway, it turned out that was messy even if I didn't have trouble
passing a block. Instead I made a method scanner(*regexs, &block) that
stores everything in an array, then later another method runs through
the list and does the actual work, where it keeps track of the
position and knows if it made a match or not. Should've slept on it
before I mailed the list!

There is no other compatible way than to explicitly pass a lambda / proc
as argument in 1.8.x:

I forgot about passing a lambda/proc as a "normal" parameter... that
would've worked though the syntax isn't as cute.

Thanks for your help Robert and Axel!

···

On 6/10/07, Robert Klemme <shortcutter@googlemail.com> wrote:

Chris Carter wrote:

···

On 6/10/07, Erwin Abbott <erwin.abbott@gmail.com> wrote:

  puts words.last # output: thre

class Proc
  def bcall(*args,&block)
    self.call(*args.concat([*block]))
  end
end

x_y = lambda {|data,proc| proc.call(data) if data.is_a? String }

x_y.bcall("hello") {|data| puts data.succ }

It's a hack, but it works.

Interesting how an ill-designed syntactic sugar forces people to jump
through the hoops.

Jenda

--
Posted via http://www.ruby-forum.com/\.

> x.call(*%w[cats dogs ones twos threes]) do |*words|
> puts words.last # output: thre
> end

Why do you need x here? Do you need to pass it around? Can you show a
bit more of the picture?

I ended up refactoring, but earlier I was parsing some text by
associating an array of attributes (like, [/a/, /b/, /c$/] that might
match the first 3 words) with a block that processed the matching
text, and then moved the position in the string forward by 3 words. I
tried wanted to be able to do this like:

Did I understand that properly, you want to process three words at a time and then the next three words? Then you could do

require 'enumerator'
words.each_slice 3 do |w1,w2,w3|
   ...
end

or

words.each_slice 3 do |three_words|
   patterns.each do |rxs, process|
     if rxs.to_enum(:zip, three_words).all? {|rx, wd| rx =~ wd}
       process[three_words]
       break
     end
   end
end

It's still unclear to me how exactly you want the matching to work. Are all your "attributes" matched against all three words? Do you positional matches? In the code all rx's are matched against words in the same position and if all match the block is invoked on the words.

match = proc do |*regexs|
if words[position..position+regexs.size] match given regexs
   parsed << yield *words[ .. ]
end
end

words = %w[the quick brown egg jumped under the slow zebra]
parsed =

while position < words.size
match.call(//, /ed/, //) do {|a, b, c| "#{a} #{b.upcase} #{c}" }
match.call(/the/, //) do {|a, b| "the #{b.upcase}" }

# increment position somewhere, maybe in match..? this was messy
end

# parsed => [the QUICK brown egg JUMPED under the SLOW zebra]

# where the matched strings were "the quick", "egg jumped under"
# and "the slow"

Anyway, it turned out that was messy even if I didn't have trouble
passing a block. Instead I made a method scanner(*regexs, &block) that
stores everything in an array, then later another method runs through
the list and does the actual work, where it keeps track of the
position and knows if it made a match or not. Should've slept on it
before I mailed the list!

There is no other compatible way than to explicitly pass a lambda / proc
as argument in 1.8.x:

I forgot about passing a lambda/proc as a "normal" parameter... that
would've worked though the syntax isn't as cute.

Thanks for your help Robert and Axel!

I still think you're not yet there.

Kind regards

  robert

···

On 10.06.2007 18:25, Erwin Abbott wrote:

On 6/10/07, Robert Klemme <shortcutter@googlemail.com> wrote:

Hmm, well, it is a feature that most languages don't have in the first
place, it exists in later versions of ruby, and I really wouldn't call
currying "jumping through hoops", its a pretty common and easy thing
to do...

···

On 6/12/07, Jenda Krynicky <jenda@cpan.org> wrote:

Chris Carter wrote:
> On 6/10/07, Erwin Abbott <erwin.abbott@gmail.com> wrote:
>> puts words.last # output: thre
>>
>
> class Proc
> def bcall(*args,&block)
> self.call(*args.concat([*block]))
> end
> end
>
> x_y = lambda {|data,proc| proc.call(data) if data.is_a? String }
>
> x_y.bcall("hello") {|data| puts data.succ }
>
> It's a hack, but it works.

Interesting how an ill-designed syntactic sugar forces people to jump
through the hoops.

Jenda

--
Posted via http://www.ruby-forum.com/\.

--
Chris Carter
concentrationstudios.com
brynmawrcs.com

> I ended up refactoring, but earlier I was parsing some text by
> associating an array of attributes (like, [/a/, /b/, /c$/] that might
> match the first 3 words) with a block that processed the matching
> text, and then moved the position in the string forward by 3 words. I
> tried wanted to be able to do this like:

Did I understand that properly, you want to process three words at a
time and then the next three words? Then you could do...

I already have solved the problem, but maybe someone will find this
useful in the future. Basically we start with position=0 (position is
the index of the words array). Each "match" is tried until one
succeeds, and the position is incremented by the number of words it
operated on. So if I called match.call(/the/, /quick/, /brown/, /.*/,
/e$/), it would read 5 words starting at "position" and if all the
arguments matched the words, it would process the 5 words in some way
and then increment the position by 5.

In my application I'm not really using regexs though, my words are
tokens with various tags, and I'm matching based on the tags. This is
all being used to pase date strings like "Wed Aug 5th 2008" might be
matched by a rule like match.call(:weekday, :month, :ordinal, :year)
for example. Then there might be another rule like match.call(:num,
:num, :year) that would match "05 05 2005" and would decide how to
parse it.

It's still unclear to me how exactly you want the matching to work. Are
all your "attributes" matched against all three words? Do you
positional matches? In the code all rx's are matched against words in
the same position and if all match the block is invoked on the words.

Basically you have it right, the words have to match their
/respective/ attribute. But it's not a fixed number of words at a
time, because match.call(/the/) would only match one word (then
process it, then increment the position index by one).

Initially (it was late at night, mind you) I though having a closure
would work nicely because I could access position, words, and some
other variables in the caller's scope and wouldn't have to pass those
along every time. But it was too tricky/messy because I also needed to
restart at the beginning of the loop after a success (to start trying
all the patterns again), and I needed to know if anything had matched
(so I could increment position by 1, else have an infinite loop).

What I ended up doing was having a function to store the list of
attributes and the block that should be called to "process" the
matching words, and then another function that began scanning the word
list from position=0, testing all the attributes (like match.call
would've), and taking care of incrementing the position index the
right amount. Here's parts of the code:

  def self.date_scanner *tags, &block
    @@date_scanners << [tags, block]
  end

  def self.setup_date_scanners
    @@date_scanners =

    date_scanner(NLTime::Day, :time, :tz) do |d, t|
      # two timezones were given, like 12:30:00 -0400 (EDT); ignore
rightmost one
      d.get_tag(NLTime::Day).time(t.get_tag(NLTime::Time))
    end

    date_scanner(NLTime::Day, :time) do |d, t|
      d.get_tag(NLTime::Day).time(t.get_tag(NLTime::Time))
    end

    date_scanner(:time, NLTime::Day) do |t, d|
      d.get_tag(NLTime::Day).time(t.get_tag(NLTime::Time))
    end

    date_scanner(:month, :num, :time, :year) do |m, a, t, y|
      # May 05 12:00:00 -0000 2005
      day = NLTime::Day.civil(a.word, m.word, y.get_tag(NLTime::Year))
      day.time(t.get_tag(NLTime::Time))
    end

    date_scanner(:year, :num, :num) do |y, a, b|
      # 2005 05 05
      NLTime::Day.civil(b.word, a.word, y.get_tag(NLTime::Year))
    end

    date_scanner(:year, :month, :num) do |y, m, a|
      # 2005 May 05
      NLTime::Day.civil(a.word, m.word, y.get_tag(NLTime::Year))
    end

    date_scanner(:month, :num, :year) do |m, a, y|
      # May 05 2005
      NLTime::Day.civil(a.word, m.word, y.get_tag(NLTime::Year))
    end

    # ...
  end

  def self.scan_dates tokens, order=:dm
    # TODO:
    # order=:dm assume day/month like american format
    # order=:md assume month/day like european format

    # processed tokens
    ptokens = ; k = 0

    while k < tokens.size
      found = false

      @@date_scanners.each do |tags, block|
        if s = tokens[-tags.size-k..-1-k]
          # assume success until one of the tags doesn't match
          found = true

          # match tags to tokens
          s.zip(tags).each do |token, tag|
            unless token.has_tag? tag
              # not a match... next scanner, please
              found = false
              break
            end
          end

          if found
            # this scanner matches, have the tokens processed
            if date = block.call(*s)
              token = NLTime::Token.new(date.to_s, :entity, date)
              ptokens.unshift token

              # increment the position by number of tokens processed
by the block
              k += tags.size

              # don't try to match any more scanners
              break
            else
              # the block failed, try the next scanner
              found = false
            end

          end
        end
      end

      unless found
        # none of the scanners matched
        ptokens.unshift tokens[-1-k]
        k += 1
      end
    end

    ptokens
  end

The scan_dates operates on an array of NLTime::Tokens, which have
various tags. The tags can be symbols, which basically categorize
words (like "Jan" would have :month tag), or they can be objects (like
we might have tagged 2005 with a NLTime::Year object representing the
year 2005). This should "replace" sequences of tokens that were
matched by a scanner with a new token, tagged with an instance of
NLTime::Day or Time.

I still think you're not yet there.

Well, my code does what I want it to do... so I'm not sure what you mean?

···

On 6/10/07, Robert Klemme <shortcutter@googlemail.com> wrote:

On 10.06.2007 18:25, Erwin Abbott wrote:

Kind regards

  robert

Chris Carter wrote:

···

On 6/12/07, Jenda Krynicky <jenda@cpan.org> wrote:

> end
Jenda

--
Posted via http://www.ruby-forum.com/\.

Hmm, well, it is a feature that most languages don't have in the first
place, it exists in later versions of ruby, and I really wouldn't call
currying "jumping through hoops", its a pretty common and easy thing
to do...

Beg your pardon? Where's there any currying in your code???
Or does Ruby have its own definition of the term different from the one
everyone else uses?

Jenda

--
Posted via http://www.ruby-forum.com/\.

I had the impression that your design or implementation still had room for improvements. From what you wrote I assume you do some kind of pattern matching. For the fun of it I coded something that solves a similar problem. Of course this could be changed in all sorts of ways (i.e. to store the pattern hash as a variable or remove the enum etc.).

Kind regards

  robert

matcher.rb (1.1 KB)

···

On 11.06.2007 22:20, Erwin Abbott wrote:

On 6/10/07, Robert Klemme <shortcutter@googlemail.com> wrote:

On 10.06.2007 18:25, Erwin Abbott wrote:
> I ended up refactoring, but earlier I was parsing some text by
> associating an array of attributes (like, [/a/, /b/, /c$/] that might
> match the first 3 words) with a block that processed the matching
> text, and then moved the position in the string forward by 3 words. I
> tried wanted to be able to do this like:

Did I understand that properly, you want to process three words at a
time and then the next three words? Then you could do...

I already have solved the problem, but maybe someone will find this
useful in the future. Basically we start with position=0 (position is
the index of the words array). Each "match" is tried until one
succeeds, and the position is incremented by the number of words it
operated on. So if I called match.call(/the/, /quick/, /brown/, /.*/,
/e$/), it would read 5 words starting at "position" and if all the
arguments matched the words, it would process the 5 words in some way
and then increment the position by 5.

In my application I'm not really using regexs though, my words are
tokens with various tags, and I'm matching based on the tags. This is
all being used to pase date strings like "Wed Aug 5th 2008" might be
matched by a rule like match.call(:weekday, :month, :ordinal, :year)
for example. Then there might be another rule like match.call(:num,
:num, :year) that would match "05 05 2005" and would decide how to
parse it.

It's still unclear to me how exactly you want the matching to work. Are
all your "attributes" matched against all three words? Do you
positional matches? In the code all rx's are matched against words in
the same position and if all match the block is invoked on the words.

Basically you have it right, the words have to match their
/respective/ attribute. But it's not a fixed number of words at a
time, because match.call(/the/) would only match one word (then
process it, then increment the position index by one).

Initially (it was late at night, mind you) I though having a closure
would work nicely because I could access position, words, and some
other variables in the caller's scope and wouldn't have to pass those
along every time. But it was too tricky/messy because I also needed to
restart at the beginning of the loop after a success (to start trying
all the patterns again), and I needed to know if anything had matched
(so I could increment position by 1, else have an infinite loop).

What I ended up doing was having a function to store the list of
attributes and the block that should be called to "process" the
matching words, and then another function that began scanning the word
list from position=0, testing all the attributes (like match.call
would've), and taking care of incrementing the position index the
right amount. Here's parts of the code:

def self.date_scanner *tags, &block
   @@date_scanners << [tags, block]
end

def self.setup_date_scanners
   @@date_scanners =

   date_scanner(NLTime::Day, :time, :tz) do |d, t|
     # two timezones were given, like 12:30:00 -0400 (EDT); ignore
rightmost one
     d.get_tag(NLTime::Day).time(t.get_tag(NLTime::Time))
   end

   date_scanner(NLTime::Day, :time) do |d, t|
     d.get_tag(NLTime::Day).time(t.get_tag(NLTime::Time))
   end

   date_scanner(:time, NLTime::Day) do |t, d|
     d.get_tag(NLTime::Day).time(t.get_tag(NLTime::Time))
   end

   date_scanner(:month, :num, :time, :year) do |m, a, t, y|
     # May 05 12:00:00 -0000 2005
     day = NLTime::Day.civil(a.word, m.word, y.get_tag(NLTime::Year))
     day.time(t.get_tag(NLTime::Time))
   end

   date_scanner(:year, :num, :num) do |y, a, b|
     # 2005 05 05
     NLTime::Day.civil(b.word, a.word, y.get_tag(NLTime::Year))
   end

   date_scanner(:year, :month, :num) do |y, m, a|
     # 2005 May 05
     NLTime::Day.civil(a.word, m.word, y.get_tag(NLTime::Year))
   end

   date_scanner(:month, :num, :year) do |m, a, y|
     # May 05 2005
     NLTime::Day.civil(a.word, m.word, y.get_tag(NLTime::Year))
   end

   # ...
end

def self.scan_dates tokens, order=:dm
   # TODO:
   # order=:dm assume day/month like american format
   # order=:md assume month/day like european format

   # processed tokens
   ptokens = ; k = 0

   while k < tokens.size
     found = false

     @@date_scanners.each do |tags, block|
       if s = tokens[-tags.size-k..-1-k]
         # assume success until one of the tags doesn't match
         found = true

         # match tags to tokens
         s.zip(tags).each do |token, tag|
           unless token.has_tag? tag
             # not a match... next scanner, please
             found = false
             break
           end
         end

         if found
           # this scanner matches, have the tokens processed
           if date = block.call(*s)
             token = NLTime::Token.new(date.to_s, :entity, date)
             ptokens.unshift token

             # increment the position by number of tokens processed
by the block
             k += tags.size

             # don't try to match any more scanners
             break
           else
             # the block failed, try the next scanner
             found = false
           end

         end
       end
     end

     unless found
       # none of the scanners matched
       ptokens.unshift tokens[-1-k]
       k += 1
     end
   end

   ptokens
end

The scan_dates operates on an array of NLTime::Tokens, which have
various tags. The tags can be symbols, which basically categorize
words (like "Jan" would have :month tag), or they can be objects (like
we might have tagged 2005 with a NLTime::Year object representing the
year 2005). This should "replace" sequences of tokens that were
matched by a scanner with a new token, tagged with an instance of
NLTime::Day or Time.

I still think you're not yet there.

Well, my code does what I want it to do... so I'm not sure what you mean?

It is essentially a curry that is called immediately. It expects the
function in question to take a function as the last argument, and
#bcall traps a block, and sets it as that last argument. The
equivalent version that "actually curries" (returns a function) would
be
class Proc
  def bcurry(&blk)
    proc { |*args| self.call(*args.concat([*block]))}
  end
end

···

On 6/13/07, Jenda Krynicky <jenda@cpan.org> wrote:

Chris Carter wrote:
> On 6/12/07, Jenda Krynicky <jenda@cpan.org> wrote:
>> > end
>> Jenda
>>
>> --
>> Posted via http://www.ruby-forum.com/\.
>>
>
> Hmm, well, it is a feature that most languages don't have in the first
> place, it exists in later versions of ruby, and I really wouldn't call
> currying "jumping through hoops", its a pretty common and easy thing
> to do...

Beg your pardon? Where's there any currying in your code???
Or does Ruby have its own definition of the term different from the one
everyone else uses?

Jenda

--
Posted via http://www.ruby-forum.com/\.

--
Chris Carter
concentrationstudios.com
brynmawrcs.com