Permalink
Browse files

docs

  • Loading branch information...
1 parent c55155c commit 5010c7b4dd23f3ba064dc52b00b607d09fc7b35f @quix committed Jun 21, 2009
Showing with 176 additions and 10 deletions.
  1. +103 −8 README.rdoc
  2. +26 −0 lib/pure.rb
  3. +47 −2 lib/pure/pure_private/singleton_features.rb
View
@@ -40,20 +40,115 @@ Language-level support for automatic parallelism and lazy evaluation.
+Pure+ is an importation of the pure functional paradigm into Ruby.
-Method names and argument names have lexicographical meaning within a
-+pure+ block. Above, the +width+ argument to +area+ corresponds by
-its literal name to the +width+ method, for example.
+Method and argument names have lexicographical meaning within a +pure+
+block. In the above example, the +width+ argument to +area+
+corresponds, by its literal name, to the +width+ method.
+pure+ returns a module which may be included into other +pure+ blocks.
Implementation details are placed inside Pure::PurePrivate, making
<tt>include Pure</tt> a hygienic operation.
-Pure does not modify any of the standard classes.
++Pure+ does not modify any of the standard classes.
-== Implementation
++Pure+ has been tested on MRI 1.8.6, 1.8.7, 1.9.1, 1.9.2, and the
+latest jruby.
-The "ripper" parser is used if it exists, otherwise ruby_parser is
-used.
+=== Dynamic names
+
+The pseudo-keyword `fun' is provided for defining a pure function
+whose name or arguments are not known at compile time. See
+Pure::PurePrivate::SingletonFeatures.
+
+== Parsing engines
+
+In order to find the names of method arguments, Pure will attempt to
+use, in this order:
+
+* Method#parameters -- available in ruby-1.9.2.
+* ripper -- available in ruby-1.9.1.
+* ruby_parser -- available in all ruby implementations (a gem).
+
+The parse engine may set be manually with <tt>Pure.engine=</tt>.
+
+== Purpose
+
+Pure has two main purposes:
+
+* Parallelize system-intensive code and/or system() calls.
+
+* A starting point for parallelizing ruby code across an arbitrary
+ number of cores and/or machines.
+
+In reference to the first point, due to the global VM lock (GVL)
+design in ruby-1.9, the actual execution of Ruby VM instructions is
+not parallelized. However when a Ruby thread is blocking (for example
+during system call), other threads will be executed.
+
+For second point, consider:
+
+ require 'pp'
+ require 'pure'
+ include Pure
+
+ adder = pure do
+ def add(left, right)
+ left + right
+ end
+ end
+
+ pp Pure::PurePrivate::FunctionDatabase[adder]
+
+output:
+
+ {:add=>
+ {:line=>8,
+ :sexp=>
+ s(:defn,
+ :add,
+ s(:args, :left, :right),
+ s(:scope,
+ s(:block,
+ s(:call, s(:lvar, :left), :+, s(:arglist, s(:lvar, :right)))))),
+ :file=>"pure_adder.rb",
+ :origin=>:def,
+ :args=>[:left, :right],
+ :name=>:add}}
+
+The basic machinery is present for distributing computations. A
+function definition and its inputs may be reconstructed
+(e.g. Ruby2Ruby and Marshal/DRb, respectively) on another core or
+computer.
+
+Note if you are using Method#parameters as the parse engine, then you
+will <em>not</em> obtain a sexp. Furthermore, I am not aware of a
+Ruby2Ruby counterpart for ripper.
+
+== Author
+
+* James M. Lawrence <quixoticsycophant@gmail.com>
+
+== License
+
+ Copyright (c) 2009 James M. Lawrence. All rights reserved.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
-Pure has been tested on MRI 1.8.6, 1.8.7, 1.9.1 and the latest jruby.
View
@@ -7,11 +7,37 @@ module Pure
module_function
+ #
+ # Create a <em>pure module</em>. The given block is evaluated in
+ # the context of the created module.
+ #
+ # A pure module is a regular Ruby module whose singleton class
+ # includes PurePrivate::SingletonFeatures and whose methods are
+ # specially registered for lexicographical checking.
+ #
+ # For the purpose of clarity, the methods of a pure module are
+ # called <em>pure functions</em>.
+ #
def pure(&block)
PurePrivate::Creator.create_module(&block)
end
class << self
+ #
+ # call-seq: engine
+ # engine=(value)
+ #
+ # Query/change the parse engine. Available engines are:
+ # * :parameters (ruby-1.9.2+ only)
+ # * :ripper (ruby-1.9 only)
+ # * :ruby_parser
+ #
+ # The default engine is tried in that order.
+ #
+ def engine # for rdoc only
+ end
+ remove_method :engine
+
[:engine, :engine=].each { |name|
define_method name, &PurePrivate::Extractor.method(name)
}
@@ -6,11 +6,56 @@
module Pure
module PurePrivate
+ #
+ # A pure module (returned by Pure.pure) has these singleton
+ # methods.
+ #
module SingletonFeatures
+ #
+ # call-seq: compute(root, n)
+ # compute(root, :threads => n)
+ #
+ # Compute a pure function with _n_ threads.
+ #
def compute(root, opts)
Driver.create_instance_and_compute(self, root, opts)
end
+ #
+ # call-seq: fun label => [label_a, label_b,...] do |arg_a, arg_b,...|
+ # ...
+ # end
+ #
+ # Define a pure function whose name and/or argument names are
+ # not known at compile time.
+ #
+ # The name of the pure function is the value of _label_. The
+ # names of the function arguments are _label_a_, _label_b_,....
+ # These are assigned to _arg_a_,_arg_b_,... respectively in the
+ # block.
+ #
+ # Example:
+ #
+ # require 'rubygems'
+ # require 'pure'
+ # include Pure
+ #
+ # stats = pure do
+ # files = Dir["*"]
+ #
+ # files.each { |file|
+ # fun file do
+ # File.size(file)
+ # end
+ # }
+ #
+ # fun :total_size => files do |*sizes|
+ # sizes.inject(0) { |acc, size| acc + size }
+ # end
+ # end
+ #
+ # p stats.compute(:total_size, 3)
+ #
def fun(*args, &block)
fun_mod = class << self ; @fun_mod ; end
node_name, child_names = (
@@ -50,13 +95,13 @@ def fun(*args, &block)
nil
end
- def method_added(function_name)
+ def method_added(function_name) #:nodoc:
FunctionDatabase[self][function_name] = (
Extractor.extract(self, function_name, caller).merge(:origin => :def)
)
end
- def define_method(*args, &block)
+ def define_method(*args, &block) #:nodoc:
raise PurePrivate::NotImplementedError,
"define_method called (use the `fun' method instead)"
end

0 comments on commit 5010c7b

Please sign in to comment.