Class: Mercury::Cps
- Inherits:
-
Object
- Object
- Mercury::Cps
- Defined in:
- lib/mercury/cps.rb,
lib/mercury/cps/seq.rb,
lib/mercury/cps/methods.rb,
lib/mercury/cps/seq_with_let.rb
Defined Under Namespace
Modules: Methods Classes: Seq, SeqWithLet
Instance Attribute Summary collapse
-
#cps ⇒ Object
readonly
Returns the value of attribute cps.
Class Method Summary collapse
-
.concurrently(*cpss) ⇒ Object
Returns a Cps that executes the provided Cpses concurrently.
-
.identity ⇒ Object
The identity function as a Cps.
-
.inject(xs, &block) ⇒ Object
equivalent to Cps.identity.inject(…).
-
.lift(&p) ⇒ Object
Returns a Cps for a non-CPS proc.
-
.seq(&block) ⇒ Object
Syntactic sugar for and_then chains.
-
.seql(&block) ⇒ Object
Syntactic sugar for and_then chains.
Instance Method Summary collapse
-
#and_lift(&p) ⇒ Object
equivalent to: and_then { lift { … } }.
-
#and_then(&pm) ⇒ Object
The “bind” operation; composes two Cps.
-
#initialize(&cps) ⇒ Cps
constructor
A new instance of Cps.
-
#inject(xs) {|x, *args| ... } ⇒ Object
Calls and_then for each x.
-
#run(*args, &k) ⇒ Object
Applies the wrapped proc.
Constructor Details
#initialize(&cps) ⇒ Cps
Returns a new instance of Cps.
21 22 23 |
# File 'lib/mercury/cps.rb', line 21 def initialize(&cps) @cps = cps end |
Instance Attribute Details
#cps ⇒ Object (readonly)
Returns the value of attribute cps.
18 19 20 |
# File 'lib/mercury/cps.rb', line 18 def cps @cps end |
Class Method Details
.concurrently(*cpss) ⇒ Object
Returns a Cps that executes the provided Cpses concurrently. Once all complete, their return values are passed to the continuation in an array with positions corresponding to the provided Cpses.
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/mercury/cps.rb', line 73 def self.concurrently(*cpss) cpss = Utils.unsplat(cpss) Cps.new do |*in_args, &k| pending_completions = cpss returned_args = [] cpss.each_with_index do |cps, i| cps.run(*in_args) do |*out_args| returned_args[i] = out_args pending_completions.delete(cps) if pending_completions.none? k.call(returned_args) end end end end end |
.identity ⇒ Object
The identity function as a Cps.
66 67 68 |
# File 'lib/mercury/cps.rb', line 66 def self.identity new { |*args, &k| k.call(*args) } end |
.inject(xs, &block) ⇒ Object
equivalent to Cps.identity.inject(…)
102 103 104 |
# File 'lib/mercury/cps.rb', line 102 def self.inject(xs, &block) Cps.identity.inject(xs, &block) end |
.lift(&p) ⇒ Object
Returns a Cps for a non-CPS proc.
54 55 56 57 58 59 60 61 62 63 |
# File 'lib/mercury/cps.rb', line 54 def self.lift(&p) new do |*args, &k| value = p.call(*args) if value.is_a?(Cps) # This is technically valid, but 99% of the time it indicates a programming error. raise "'lift' block returned a Cps object. Did you want 'and_then'? at #{p.source_location}" end k.call(value) end end |
.seq(&block) ⇒ Object
Syntactic sugar for and_then chains.
5 6 7 8 9 |
# File 'lib/mercury/cps/seq.rb', line 5 def self.seq(&block) s = Seq.new block.call(s.method(:chain)) s.m end |
.seql(&block) ⇒ Object
Syntactic sugar for and_then chains.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# File 'lib/mercury/cps/seq_with_let.rb', line 4 def self.seql(&block) # EXPERIMENTAL # The trick here is to execute the block in a context where # 1. we can simulate local let-bound variables, and # 2. the block can access variables and methods available # outside the call to seql. # # To achieve this, we instance_exec the block in a SeqWithLet # object, which provides the let bound variables (as methods) # and uses method_missing to proxy other methods to the parent # binding. # # Note: parent instance variables are not available inside the block. # Note: keyword arguments are not proxied to methods called in the parent binding context = SeqWithLet.new(block.binding) context.instance_exec(&block) context.__chain end |
Instance Method Details
#and_lift(&p) ⇒ Object
equivalent to: and_then { lift { … } }
47 48 49 50 51 |
# File 'lib/mercury/cps.rb', line 47 def and_lift(&p) and_then do |*args| Cps.lift { p.call(*args) } end end |
#and_then(&pm) ⇒ Object
The “bind” operation; composes two Cps
36 37 38 39 40 41 42 43 44 |
# File 'lib/mercury/cps.rb', line 36 def and_then(&pm) Cps.new do |*args, &k| self.run(*args) do |*args2| next_cps = pm.call(*args2) next_cps.is_a?(Cps) or raise "'and_then' block did not return a Cps object. Did you want 'and_lift'? at #{pm.source_location}" next_cps.run(&k) end end end |
#inject(xs) {|x, *args| ... } ⇒ Object
Calls and_then for each x.
95 96 97 98 99 |
# File 'lib/mercury/cps.rb', line 95 def inject(xs, &block) xs.inject(self) do |chain, x| chain.and_then { |*args| block.call(x, *args) } end end |
#run(*args, &k) ⇒ Object
Applies the wrapped proc. If the CPS return value is not needed, the continuation k may be omitted. Returns the return value of the continuation.
28 29 30 31 |
# File 'lib/mercury/cps.rb', line 28 def run(*args, &k) k ||= proc { |x| x } cps.call(*args, &k) end |