Created
September 17, 2011 20:59
-
-
Save josevalim/1224361 to your computer and use it in GitHub Desktop.
Partial application on rubinius. Apply the diff to rubinius project and run `rake build`. Idea by @josevalim, code by @wycats.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Sean, what is Haskell's 'cut'?
@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).
@seancribbs cool, I didn't know Erlang could do that stuff.
@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
AKA "cut" in Haskell? Pretty awesome.