hoodwink.d enhanced
RSS
2.0
XHTML
1.0

RedHanded

Arity Makes Good Curry #

by why in inspect

kig just dropped this snip in the comments of the pipes discussion, which had morphed into a discussion about functional programming.

 class Fun < Proc
   def call(*args)
     if args.size < arity.abs and arity != -1
       Fun.new{|*a| call(*(args+a)) }
     else
       super
     end
   end
   alias_method :[], :call
 end

 def fun &block
   Fun.new &block
 end

 f = fun{|a, b, c| a * b / c }

 f[10, 20, 30] == f[10][20][30]
 #=> true

You can sort of curry methods with this, like so:

 class Turtle
   def draw *args
     fun { |x, y| ... }.call(*args)
   end
 end

But you will need to use the bracket syntax on the function returned by the method.

said on

f = fun {|a, b, *c| [a, b, *c] }
f[1,2] #=> #&lt;Fun:0x02b4ec58> :(
For consistency, and the ability to call *args functions with empty args:

#...
  def call(*args)
 if args.size < arity.abs and args.size != -arity - 1
#...

I predict that the thread below will contain an improved recipe for method currying, so stay tuned!

said on

Oho, good point with -arity. Another thing would be handling block arguments, any idea with that? E.g.

f = fun{|x, &b| x.map(&b) }
double = f.call{|i| i*2 }
double[[1,2,3]]
#=> [2,4,6]
said on

Exactly what you posted will work in Ruby 1.9, but procs can’t take blocks in 1.8.

said on

Pardon, but where is arity defined?

said on

arity is a method of Proc and Method and UnboundMethod.

said on

Here’s arity in Programming Ruby’s online reference if you want to be specific about it.

said on
Continuing with funny thought code experiments, how about mixing Enumerables and Procs?

class Proc
include Enumerable
  attr_accessor :domain
  def each
    domain.each{|*e| yield call(*e) }
  end
  alias_method :range, :entries
end

f = lambda{|x| x * 2 }
f.domain = (1..5)
f.range
#=> [2, 4, 6, 8, 10]

g = lambda{|y| y - 1 }
g.domain = f
g.range
#=> [1, 3, 5, 7, 9]
said on
Of course we could just do

class Proc
  def >> g
    lambda{|*args| g[self[*args]]}
  end
  def over enum
    enum.map &self
  end
end

f = lambda{|x| x * 2 }
g = lambda{|y| y - 1 }
h = f >> g
h.over(1..5)
#=> [1, 3, 5, 7, 9]
But it just doesn’t have the same feeling, somehow.
said on

On Suby we discussed a bit we picked up from Nemerle:

def foo( x, y )
  x + y
end
bar = foo( _, 10 )
bar( 6 )  #=> 16

Apply it too lambdas just as well. Would be a cool feature.

said on

Okay, so we’ve got:

  • monads
  • lazy evaluation
  • automatic currying
  • function composition (via kig’s >> operator)

Any other “scary” functional programming things left to do in Ruby? Because I feel like we are running out.

I mean, I suppose we could always do the old “Ruby Objects are really just functions” routine.


class Object
  alias call send
  alias [] call
  def arity ; -1 ; end
  def to_proc ; method( :send ).to_proc ; end
end

Y’know, because they are. They’re closures over their instance variables. Their first parameter is a method name.

p [ :inspect, :class, [ :'+', 2 ] ].map( &1 )
 => ["1", Fixnum, 3]
said on

(Once we’re done here I think I’m going to make a raskell.rb with all this stuff in. Just for kicks.)

said on

Incidentally, once you see that objects are functions, it’s apparent that Object#method simply curries in the first argument.

said on

Any other “scary” functional programming things left to do in Ruby? Because I feel like we are running out.

Hindley-Milner type inference? I kid, I kid.

The Objects as functions -trick made me giggle with glee, good job.

I found the following amusing:


f = fun{|x| x * 2 }
f.domain = (1..5)

g = fun{|x| x - 2 }
g.domain = (3..7)

h = fun{|x,y| x * y }
h.domain = f

h.zip(g).map{|f,x| f[x] }
#=> [2, 8, 18, 32, 50]
said on

Haskell-style datatype.rb still seems to have room for improvement(cvs.m17n.org/viewcvs/ruby/).

said on

Here is a functional-style one-liner to create n-dim arrays:

md = lambda {|*ds| Array::new(ds.shift || 0).map {md[ds] unless ds.empty? }}; nar = md.call(8, 3, 5); puts nar.inspect

said on

correction: ... md[*ds] ...

said on

(Once we’re done here I think I’m going to make a raskell.rb with all this stuff in. Just for kicks.)

Yes!! Please.

Comments are closed for this entry.