Issue #6253 has been updated by jballanc (Joshua Ballanco).


=begin
I still want to think about this problem some more, but I also wanted to share some of my early thoughts...

I think that part of the problem with currying in Ruby is that we don't have the sort of type system that makes curried Procs so useful in languages like OCaml. For example, if you have a function in OCaml with the signature (({(A -> B -> C) -> (B -> C)})), then you have a guarantee that you can apply an instance of A to the first argument, and the result will still be a function. In Ruby, if you have a method defined like (({def foo(a_proc)})), and you #call the proc passed in, you can't know whether the result will still be a proc or whether it will be the result of executing the proc. For this reason, it makes far more sense to simply wrap procs in procs:

    def takes_curry(a_proc)
      a_proc.call('hello') # <-- might return a value, or a proc
    end
    
    def takes_proc(a_proc)
      proc do |other_arg|
        a_proc.call('hello', other_arg)
      end
      # ^ definitely returns a proc that takes one more argument
    end

However, I don't think that means that currying procs in Ruby is useless. On the contrary, now that we have keyword arguments, I think that a curried proc could make a very compelling substitute for the method object pattern:

    class NightParams
      def self.parameterize(meth)
        meth.greeting = 'Goodnight'
      end
    end
    
    class QuestionParams
      def self.parameterize(meth)
        meth.punctuation = '?'
      end
    end
    
    def parameterize_and_call(parameterizer, name)
      method = proc do |name, greeting: 'Hello', punctuation: '!'|
        puts "#{greeting}, #{name}#{punctuation}"
      end.curry
      parameterizer.parameterize(method)
      method.call(name)
    end
    
    parameterize_and_call(NightParams, 'moon') #=> "Goodnight, moon!"
    parameterize_and_call(QuestionParams, 'Joe') #=> "Hello, Joe?"

Any thoughts?
=end

----------------------------------------
Feature #6253: Implement a way to pass keyword options to curried procs
https://bugs.ruby-lang.org/issues/6253#change-26019

Author: jballanc (Joshua Ballanco)
Status: Assigned
Priority: Normal
Assignee: matz (Yukihiro Matsumoto)
Category: core
Target version: 2.0.0


=begin
(See original discussion in issue #4610)

With the introduction of keyword arguments in Ruby 2.0, it would be useful to have a way to set a keyword-based option on a curried proc. The example below demonstrates a Rack-like system where a curried proc is passed to a helper, then after partial application of the arguments, the returned curried proc is stored and later evaluated:

    class NicknameTranslator
      def initialize(app)
        @app = app
      end
    
      def call(name)
        case name
        when 'Robert'
          @app.call('Bob')
        when 'James'
          @app.call('Jimmy')
        else
          @app.call(name)
        end
      end
    end
    
    class NightGreeting
      def initialize(app)
        @app = app
        @app.pass_option(greeting: 'Goodnight')
      end
    
      def call(name)
        @app.call(name)
      end
    end
    
    class Greeter
      def initialize(helper)
        @helper = helper
        @app = lambda do |sender, receiver, greeting: 'Hello'|
          puts "#{sender} says \"#{greeting}\" to #{receiver}"
        end.curry
        @greetings = {}
      end
    
      def call(sender, receiver)
        @greetings[sender] ||= @helper.new(@app).call(sender)
        @greetings[sender].call(receiver)
      end
    end
    
    Greeter.new(NicknameTranslator).call('Josh', 'Joe')
    Greeter.new(NicknameTranslator).call('Robert', 'Joe')
    Greeter.new(NicknameTranslator).call('Josh', 'Robert')

If we wanted, however, to be able to set a keyword-based option in the helper, there is currently no way in Ruby 2.0 to do so. Currently, keyword arguments can only be used at the same time as the final non-keyword, non-default, non-rest argument to the proc is applied. So, for example, there is no way to do the above with NightGreeting in place of NicknameTranslator.

Currying is really only useful when it can be used with partial application. However, Ruby currently limits how you can achieve partial application of curried procs. In particular, there is no way to manage partial application of parameters with default values. As such, it is not surprising that Proc#curry does not seem to have been adopted very widely. In my personal survey of ~600 gems that I use in various projects, I did not find any usage of Proc#curry.

So, I would request a method like Proc#pass_option (or some other, better name) that allows for setting keyword arguments on a curried proc at any time.
=end



-- 
http://bugs.ruby-lang.org/