Partial function application (was: Re: Binding precedence for first sym...)

Lähettäjä: Matt Maycock <ummaycoc@gmail.com>
Aihe: Re: Partial function application (was: Re: Binding precedence for first sym...)

> Douglas Livingstone wrote:
> > How about this:
> >
> > def fun(z)
> > x = 1
> > y = 2
> >
> > # unmodified original
> > x = x + y + z
> > end
> >
> > Then you shouldn't need to worry about rewriting as they would act
> > more like defult params.
>
> Nice.

This isn't even what he was asking for, though. The OP wanted a
`saved arguments' thing like currying... hardcoding in x and y is the
same as hardcoding 1 and 2 in the q (or x in OP's one example) = x +
y+ z...

Also, I've made a few small updates to my curry file, if anyone is
interested (just default behaviors for certain methods invoked without
any information to use).

Here's a naive, slightly more straightforward implementation
(entirely untested):

···

On Wed, 2 Feb 2005 02:50:44 +0900, Trans <transfire@gmail.com> wrote:

########################

# class Proc / Extension
# -- Extend Proc to enable currying.
# If a block is invoked with too few arguments, it is
# automatically converted to a 'new' block with the
# given arguments bound to it in the fashion of currying.
# If skipping an argument is desired, :_ can be used as
# a placeholder:
#
# p = Proc.new {|a, b, c| a + b + c}
#
# p1 = p.call(1, 2) # ~ Proc.new {|c| 1 + 2 + c}
# p2 = p.call(1, :_, 3) # ~ Proc.new {|b| 1 + b + 3}
#
# p.call(1, 2, 3) # => 6
# p1.call(3) # => 6
# p2.call(2) # => 6
#
class Proc

  alias :proc_init :initialize
  alias :proc_call :call

  # initialize / Constructor
  # -- Create a normal Proc object and
  # initialize currying handling.
  def initialize(&block)
    # Initialize the block normally
    proc_init &block

    # Set up currying
    ar = block.arity

    # Block accepts any number of arguments?
    @catchall if ar < 0

    # Number of required arguments
    @available = ar < -1 ? ar.abs : ar.abs - 1

    # Set up the argument placeholders
    @args = Array.new @available, :_
  end

# Interface
public

  # call / Interface method
  # -- Attempt to execute the method. If all required
  # arguments have not been received, the block will
  # be executed, otherwise the block will be curried
  # from the collected arguments.
  def call(*args)
    # Bind the remaining arguments
    bind_vars args

    # Curry if all arguments are not present
    return self if @available > 0
   
    # Execute the block with the collected args
    proc_call @args
  end

  # / Interface method
  # -- Synonym for #call
  alias : :call

  # curry / Interface method
  # -- Explicitly curries the block from the given args.
  def curry(*args)
    # Bind only
    bind_vars args
  end

  # bind / Interface method
  # -- Synonym for #curry
  alias :bind :curry

# Internals
private

  # bind_vars / Internal method
  # -- Store the arguments given for future use.
  def bind_vars(args)
    # Ensure there are enough available slots
    raise ArgumentError if (@available -= args.length) < 0 and not @catchall
    
    # Replace the placeholders with the given arguments
    @args.map! do |arg|
      args.shift.dup if arg == :_ and
    end

    # Accept any remaining arguments if the block can take them
    @args << args if @catchall
  end

end # class Proc

########################

The main issue, of course, is that extra syntax would be required
to be able to curry methods rather than blocks. Once either () becomes
overridable or something of that tune, this is more of a curiosity.

Then there's of course the age-old question whether this is in any
way a necessary addition to the language. It'd be nice to have an
end-all-be-all language but some features just don't jive together.
This one might.

Given that the OP mentioned Haskell, I think we should all try to come
up with some language that has the wonderfulness of Haskell with the
wonderful ness of Ruby. We could call it Rascal. Since Haskell cats
are all about domain specific languages, we could call DSLs in Rascal
"Little Rascals"... :slight_smile:

Apparently merd (www.merd.net) is trying to fill this niche. The
documentation is very sparse, though.

~Me!

E