From: Ross Bamford Date: 2006-02-03T00:03:40+09:00 Subject: Re: [SUMMARY] Port a Library (#64) --=-A9o5LUnH35uVuOD+R6gv Content-Type: text/plain Content-Transfer-Encoding: 7bit On Thu, 2006-02-02 at 22:37 +0900, Ruby Quiz wrote: > The library already supports a bunch of "spices", like HOLE above, but > you can also add your own: > > # Lazy Evaluation meets Currying... > class LazySpice < Curry::SpiceArg > def initialize( &promise ) > super("LAZYSPICE") > > @promise = promise > end > > def spice_arg( args ) # called to provide the missing argument > [@promise.call] > end > end > > logger = lambda do |time, message| > puts "[#{time.strftime('%I:%M:%S %p %m/%d/%y')}] #{message}" > end > > log_now = logger.curry(LazySpice.new { Time.now }) > > log_now["First Message."] # => [12:47:53 PM 02/01/06] First Message. > sleep 3 > log_now["Second Message."] # => [12:47:56 PM 02/01/06] Second Message. > > Notice how the LazySpice isn't evaluated until the time of the call. That lazy > execution makes sure our message is stamped with the time it was actually > logged. This is very cool, thanks for the great write-up. However, there is a small bug (in curry.rb, not this code) that can cause problems with this, e.g: a = [1,3,5] b = [2,4,6] l = lambda do |ary,aa,ba| ary + [aa,ba] end.curry(Curry::HOLE,Curry::HOLE,TestSpice.new { b.shift }) l.call # => [1,nil,3,nil,5,nil] (expected: 1,2,3,4,5,6) This only shows up when special spices are at the end of the argument list, and happens because there are no args_remain left by the time they're seen, and I took a short-cut in the implementation. The attached patch (against the documented version from http://roscopeco.co.uk/code/ruby-quiz-entries/64/curry.rb) fixes things. There maybe a slight impact on performance, though (if that matters). I'm considering maybe packaging Ruby Murray up as a gem and releasing it on RubyForge. I'll add James' LazySpice, and would like any suggestions others may have (esp if anyone has something we could legitimately call "SportySpice" ;D) Thanks again for the quiz. Cool entries everyone :) -- Ross Bamford - rosco@roscopeco.REMOVE.co.uk --=-A9o5LUnH35uVuOD+R6gv Content-Disposition: attachment; filename=0.1.0-0.1.2.patch Content-Type: text/x-patch; name=0.1.0-0.1.2.patch; charset=utf-8 Content-Transfer-Encoding: 7bit --- curry-orig.rb 2006-02-02 14:45:23.000000000 +0000 +++ curry.rb 2006-02-02 14:40:39.000000000 +0000 @@ -7,7 +7,14 @@ # # You can download Ruby Murray (with documentation and explanatory # comments) from http://roscopeco.co.uk/ruby-quiz-entries/64/curry.rb - +# +# == Changelog +# +# 0.1.0 - 2005/01/27 - First version +# 0.1.2 - 2005/02/02 - Changed call_spice behaviour when processing +# leftover SpiceArgs, arg is now called with +# no remaining args. +# require 'singleton' # *Ruby* *Murray* is a Ruby port of Perl's Sub::Curry library that allows @@ -235,11 +242,11 @@ # Merges, then resolves all special spices def call_spice(args) sp = merge_spice(args) - sp.map do |a| + sp.inject([]) do |ary, a| if a.is_a? SpiceArg - nil + ary + a.spice_arg([]) else - a + ary << a end end end @@ -442,6 +449,24 @@ s = Sub::Curry.new(s.method(:+), "ing") assert_equal "string", s.call end + + class TestSpice < Curry::SpiceArg + def initialize(&blk) + @blk = blk + end + def spice_arg(args_remain) + [@blk.call] + end + end + + def test_spice_at_end_regression + a = [1,3,5] + b = [2,4,6] + l = lambda { |ary,aa,ba| ary + [aa,ba] }.curry(Curry::HOLE,Curry::HOLE,TestSpice.new { b.shift }) + + # bug behaviour: assert_equal [1,nil,3,nil,5,nil] + assert_equal [1,2,3,4,5,6], a.inject([], &l) + end end if ARGV.member?('--doc') || !File.exist?('doc') --=-A9o5LUnH35uVuOD+R6gv--