Partial application on rubinius. Apply the diff to rubinius project and run `rake build`. Idea by @josevalim, code by @wycats.
diff --git a/lib/compiler/ast/transforms.rb b/lib/compiler/ast/transforms.rb | |
index 19e1cfb..4e52ec2 100644 | |
--- a/lib/compiler/ast/transforms.rb | |
+++ b/lib/compiler/ast/transforms.rb | |
@@ -59,6 +59,71 @@ module Rubinius | |
end | |
end | |
+ # Provide an underscore node that allows partial application in Ruby. | |
+ # Instead of doing a method call, we are going to generate a lambda | |
+ # that allow us to pass argument where undercores were placed. | |
+ # | |
+ # Conceptual examples: | |
+ # | |
+ # puts(_) | |
+ # #=> lambda { |x| puts(x) } | |
+ # | |
+ # self.puts(_) | |
+ # #=> lambda { |x| self.puts(x) } | |
+ # | |
+ # object.puts(_) | |
+ # #=> lambda { |x| object.puts(x) } | |
+ # | |
+ # puts(_, :a, _) | |
+ # #=> lambda { |x,y| self.puts(x, :a, y) } | |
+ # | |
+ # Practical examples: | |
+ # | |
+ # [1,2,3].each &puts(_) | |
+ # #=> 1\n2\n3\n | |
+ # | |
+ # { :send => true, :to_s => false }.select &object.respond_to?(_, _) | |
+ # #=> [:send, :to_s] | |
+ # | |
+ class Underscore < SendWithArguments | |
+ transform :default, :underscore, "Partial application using _" | |
+ | |
+ def self.match?(line, receiver, name, arguments, privately) | |
+ return nil unless arguments.is_a?(ArrayLiteral) | |
+ | |
+ if arguments.body.size > 0 && arguments.body.any? { |arg| arg.is_a?(Send) && arg.name == :_ } | |
+ ret = new line, receiver, name, arguments, privately | |
+ end | |
+ end | |
+ | |
+ def bytecode(g) | |
+ block_args = [] | |
+ arg = 0 | |
+ | |
+ send_args = [] | |
+ | |
+ arguments.array.each do |argument| | |
+ if argument.instance_of?(Send) && argument.name == :_ | |
+ block_args << LocalVariableAssignment.new(line, :"_partial#{arg}_", nil) | |
+ send_args << LocalVariableAccess.new(line, :"_partial#{arg}_") | |
+ arg += 1 | |
+ else | |
+ send_args << argument | |
+ end | |
+ end | |
+ | |
+ send_args = ArrayLiteral.new(line, send_args) | |
+ | |
+ masgn = MultipleAssignment.new(line, ArrayLiteral.new(line, block_args), nil, nil) | |
+ masgn.iter_arguments | |
+ | |
+ send_node = SendWithArguments.new(line, receiver, name, send_args, privately) | |
+ iter = Iter.new(line, masgn, send_node) | |
+ | |
+ iter.bytecode(g) | |
+ end | |
+ end | |
+ | |
## | |
# Handles Rubinius.primitive | |
class SendPrimitive < SendWithArguments |
This comment has been minimized.
This comment has been minimized.
Sean, what is Haskell's 'cut'? |
This comment has been minimized.
This comment has been minimized.
@akahn It's a pattern for partial application that uses the underscore (sorry, I was mistaken, it came from Scheme). There's a beautiful port of the idea to Erlang (which also includes monads) called erlando (video/slides). |
This comment has been minimized.
This comment has been minimized.
@seancribbs cool, I didn't know Erlang could do that stuff. |
This comment has been minimized.
This comment has been minimized.
@akahn Yeah, it has functions called "parse transforms" that can be run on the AST to transform it before it reaches the bytecode transformation step. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
AKA "cut" in Haskell? Pretty awesome.