aanand-ruby-do-notation 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,15 @@
1
+ lib/do_notation/monad.rb
2
+ lib/do_notation/monad_plus.rb
3
+ lib/do_notation/monads/array.rb
4
+ lib/do_notation/monads/maybe.rb
5
+ lib/do_notation/monads/simulations.rb
6
+ lib/do_notation/rewriter.rb
7
+ lib/do_notation.rb
8
+ README.markdown
9
+ test/array.rb
10
+ test/maybe.rb
11
+ test/monad_plus.rb
12
+ test/simulations.rb
13
+ test/spec_helper.rb
14
+ test/specs.rb
15
+ Manifest
@@ -0,0 +1,34 @@
1
+ Haskell-style monad do-notation for Ruby
2
+ ========================================
3
+
4
+ Example:
5
+
6
+ class Array
7
+ include Monad
8
+
9
+ def self.unit x
10
+ [x]
11
+ end
12
+
13
+ def bind &f
14
+ map(&f).inject([]){ |a,b| a+b }
15
+ end
16
+ end
17
+
18
+ Array.run do
19
+ x <- ["first", "second"]
20
+ y <- ["once", "twice"]
21
+
22
+ unit("#{x} cousin #{y} removed")
23
+ end
24
+
25
+ The above code returns the array:
26
+
27
+ ["first cousin once removed",
28
+ "first cousin twice removed",
29
+ "second cousin once removed",
30
+ "second cousin twice removed"]
31
+
32
+ For more examples, see the test suite.
33
+
34
+ By Aanand Prasad (aanand.prasad@gmail.com)
@@ -0,0 +1,9 @@
1
+ $: << File.dirname(__FILE__)
2
+
3
+ require 'rubygems'
4
+ require 'parse_tree'
5
+ require 'sexp_processor'
6
+ require 'ruby2ruby'
7
+
8
+ require 'do_notation/rewriter'
9
+ require 'do_notation/monad'
@@ -0,0 +1,24 @@
1
+ module Monad
2
+ module ClassMethods
3
+ def run &block
4
+ eval(ruby_for(block), block).call
5
+ end
6
+
7
+ def ruby_for block
8
+ @cached_ruby ||= {}
9
+ @cached_ruby[block.to_s] ||= "#{self.name}.instance_eval { #{Ruby2Ruby.new.process(Rewriter.new.process(block.to_method.to_sexp)[2])} }"
10
+ end
11
+ end
12
+
13
+ def bind_const &block
14
+ bind { |_| block.call() }
15
+ end
16
+
17
+ def >> n
18
+ bind_const { n }
19
+ end
20
+
21
+ def self.included m
22
+ m.extend ClassMethods
23
+ end
24
+ end
@@ -0,0 +1,9 @@
1
+ module MonadPlus
2
+ def guard p
3
+ if p
4
+ unit(mzero)
5
+ else
6
+ mzero
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,21 @@
1
+ require 'do_notation/monad_plus'
2
+
3
+ class Array
4
+ include Monad
5
+
6
+ def self.unit x
7
+ [x]
8
+ end
9
+
10
+ def bind &f
11
+ map(&f).inject([]){ |a,b| a+b }
12
+ end
13
+
14
+ extend MonadPlus
15
+
16
+ def self.mzero
17
+ []
18
+ end
19
+
20
+ alias_method :mplus, :+
21
+ end
@@ -0,0 +1,31 @@
1
+ require 'do_notation/monad_plus'
2
+
3
+ class Maybe < Struct.new(:value)
4
+ include Monad
5
+
6
+ def self.unit value
7
+ self.new(value)
8
+ end
9
+
10
+ def bind &f
11
+ if value.nil?
12
+ self
13
+ else
14
+ f.call(value)
15
+ end
16
+ end
17
+
18
+ extend MonadPlus
19
+
20
+ def self.mzero
21
+ unit(nil)
22
+ end
23
+
24
+ def mplus m
25
+ if value.nil?
26
+ m
27
+ else
28
+ self
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,117 @@
1
+ # converted from Mauricio Fernandez's "Warm fuzzy things for random simulations":
2
+ # http://eigenclass.org/hiki/warm-fuzzy-things-for-random-simulations
3
+ # http://eigenclass.org/hiki.rb?c=plugin;plugin=attach_download;p=warm-fuzzy-things-for-random-simulations;file_name=fuzzy-warm-simulations.rb
4
+
5
+ module PRNG
6
+ def next_state(s); (69069 * s + 5) % (2**32) end
7
+ end
8
+
9
+ class Simulation
10
+ extend PRNG
11
+ include Monad
12
+
13
+ attr_reader :f
14
+
15
+ def initialize(&b)
16
+ @f = b
17
+ end
18
+
19
+ def self.unit(x)
20
+ new { |s| [x, s] }
21
+ end
22
+
23
+ def self.rand(n)
24
+ self.new do |s|
25
+ [s.abs % n, next_state(s)]
26
+ end
27
+ end
28
+
29
+ def bind(&b)
30
+ self.class.new do |s|
31
+ x, s = @f.call(s)
32
+ b.call(x).f.call(s)
33
+ end
34
+ end
35
+
36
+ def play(s = 12345)
37
+ @f.call(s).first
38
+ end
39
+ end
40
+
41
+ class Distribution
42
+ extend PRNG
43
+ include Monad
44
+
45
+ attr_reader :a
46
+
47
+ def initialize(a)
48
+ @a = a
49
+ end
50
+
51
+ def self.wrap(a)
52
+ new(a)
53
+ end
54
+
55
+ def self.unit(x)
56
+ wrap [[x, 1.0]]
57
+ end
58
+
59
+ def self.rand(n)
60
+ p = 1.0 / n
61
+ new((0...n).map{|i| [i, p]})
62
+ end
63
+
64
+ def bind(&b)
65
+ if @a.empty?
66
+ self.class.wrap([])
67
+ else
68
+ x, p = @a[0]
69
+ self.class.wrap(mulp(p, b.call(x)) + self.class.new(@a[1..-1]).bind(&b).a)
70
+ end
71
+ end
72
+
73
+ def play
74
+ h = Hash.new{|h, k| h[k] = 0.0}
75
+ @a.each{|x, p| h[x] += p}
76
+ h.to_a.sort_by{|x,| x}
77
+ end
78
+
79
+ private
80
+ def mulp(p, l)
81
+ l.a.map{|x, p1| [x, p * p1]}
82
+ end
83
+ end
84
+
85
+ class Expectation
86
+ extend PRNG
87
+ include Monad
88
+
89
+ attr_reader :f
90
+
91
+ def initialize(&b)
92
+ @f = b
93
+ end
94
+
95
+ def self.wrap(&proc)
96
+ new(&proc)
97
+ end
98
+
99
+ def self.unit(x)
100
+ wrap{ |f| f.call(x) }
101
+ end
102
+
103
+ def self.rand(n)
104
+ wrap do |k|
105
+ sum = (0..n-1).map{|x| k.call(x)}.inject{|s,x| s+x}
106
+ 1.0 * sum / n
107
+ end
108
+ end
109
+
110
+ def bind(&b)
111
+ self.class.wrap{|k| @f.call(lambda{|x| b.call(x).f.call(k)}) }
112
+ end
113
+
114
+ def play(x)
115
+ @f.call(lambda{|x1| x1 == x ? 1.0 : 0.0})
116
+ end
117
+ end
@@ -0,0 +1,63 @@
1
+ class Rewriter < SexpProcessor
2
+ def process_bmethod exp
3
+ type = exp.shift
4
+
5
+ exp.shift # throw away arguments
6
+
7
+ body = process(exp.shift)
8
+
9
+ if body[0] == :block
10
+ body.shift
11
+ else
12
+ body = s([*body])
13
+ end
14
+
15
+ s(:iter, s(:fcall, :proc), nil, *rewrite_assignments(body))
16
+ end
17
+
18
+ def rewrite_assignments exp
19
+ return [] if exp.empty?
20
+
21
+ head = exp.shift
22
+
23
+ if head.first == :call and head[1].first == :vcall and head[2] == :< and head[3].first == :array and head[3][1].last == :-@
24
+ var_name = head[1][1]
25
+ expression = head[3][1][1]
26
+
27
+ body = rewrite_assignments(exp)
28
+
29
+ if body.first.is_a? Symbol
30
+ body = [s(*body)]
31
+ end
32
+
33
+ [s(:iter,
34
+ s(:call, process(expression), :bind),
35
+ s(:dasgn_curr, var_name),
36
+ *body)]
37
+ elsif exp.empty?
38
+ [process(head)]
39
+ else
40
+ [s(:iter, s(:call, process(head) , :bind_const), nil ,
41
+ *rewrite_assignments(exp)) ]
42
+ end
43
+ end
44
+
45
+ def self.pp(obj, indent='')
46
+ return obj.inspect unless obj.is_a? Array
47
+ return '()' if obj.empty?
48
+
49
+ str = '(' + pp(obj.first, indent + ' ')
50
+
51
+ if obj.length > 1
52
+ str << ' '
53
+
54
+ next_indent = indent + (' ' * str.length)
55
+
56
+ str << obj[1..-1].map{ |o| pp(o, next_indent) }.join("\n#{next_indent}")
57
+ end
58
+
59
+ str << ')'
60
+
61
+ str
62
+ end
63
+ end
@@ -0,0 +1,59 @@
1
+
2
+ # Gem::Specification for Ruby-do-notation-0.1
3
+ # Originally generated by Echoe
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = %q{ruby-do-notation}
7
+ s.version = "0.1"
8
+
9
+ s.specification_version = 2 if s.respond_to? :specification_version=
10
+
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
+ s.authors = ["Aanand Prasad"]
13
+ s.date = %q{2008-06-20}
14
+ s.description = %q{Haskell-style monad do-notation for Ruby}
15
+ s.email = %q{aanand.prasad@gmail.com}
16
+ s.extra_rdoc_files = ["lib/do_notation/monad.rb", "lib/do_notation/monad_plus.rb", "lib/do_notation/monads/array.rb", "lib/do_notation/monads/maybe.rb", "lib/do_notation/monads/simulations.rb", "lib/do_notation/rewriter.rb", "lib/do_notation.rb", "README.markdown"]
17
+ s.files = ["lib/do_notation/monad.rb", "lib/do_notation/monad_plus.rb", "lib/do_notation/monads/array.rb", "lib/do_notation/monads/maybe.rb", "lib/do_notation/monads/simulations.rb", "lib/do_notation/rewriter.rb", "lib/do_notation.rb", "README.markdown", "test/array.rb", "test/maybe.rb", "test/monad_plus.rb", "test/simulations.rb", "test/spec_helper.rb", "test/specs.rb", "Manifest", "ruby-do-notation.gemspec"]
18
+ s.has_rdoc = true
19
+ s.homepage = %q{http://github.com/aanand/ruby-do-notation/tree/master}
20
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Ruby-do-notation", "--main", "README.markdown"]
21
+ s.require_paths = ["lib"]
22
+ s.rubyforge_project = %q{ruby-do-notation}
23
+ s.rubygems_version = %q{1.1.0}
24
+ s.summary = %q{Haskell-style monad do-notation for Ruby}
25
+
26
+ s.add_dependency(%q<ParseTree>, [">= 0"])
27
+ s.add_dependency(%q<ruby2ruby>, [">= 0"])
28
+ end
29
+
30
+
31
+ # # Original Rakefile source (requires the Echoe gem):
32
+ #
33
+ # require 'spec/rake/spectask'
34
+ #
35
+ # spec_list = FileList['test/*.rb']
36
+ #
37
+ # task :default => :test
38
+ #
39
+ # desc "Run all specs"
40
+ # Spec::Rake::SpecTask.new('spec') do |t|
41
+ # t.spec_files = spec_list
42
+ # end
43
+ #
44
+ # desc "Run all specs with RCov"
45
+ # Spec::Rake::SpecTask.new('rcov') do |t|
46
+ # t.spec_files = spec_list
47
+ # t.rcov = true
48
+ # end
49
+ #
50
+ # require 'echoe'
51
+ #
52
+ # Echoe.new('ruby-do-notation') do |p|
53
+ # p.author = 'Aanand Prasad'
54
+ # p.summary = 'Haskell-style monad do-notation for Ruby'
55
+ # p.email = 'aanand.prasad@gmail.com'
56
+ # p.url = 'http://github.com/aanand/ruby-do-notation/tree/master'
57
+ # p.version = '0.1'
58
+ # p.dependencies = ['ParseTree', 'ruby2ruby']
59
+ # end
@@ -0,0 +1,18 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+ require 'do_notation/monads/array'
3
+
4
+ describe "Array:" do
5
+ specify "all results are calculated and concatenated" do
6
+ array = Array.run do
7
+ x <- ["first", "second"]
8
+ y <- ["once", "twice"]
9
+
10
+ unit("#{x} cousin #{y} removed")
11
+ end
12
+
13
+ array.should == ["first cousin once removed",
14
+ "first cousin twice removed",
15
+ "second cousin once removed",
16
+ "second cousin twice removed"]
17
+ end
18
+ end
@@ -0,0 +1,26 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+ require 'do_notation/monads/maybe'
3
+
4
+ describe "Maybe:" do
5
+ specify "one or more nils results in nil" do
6
+ maybe = Maybe.run do
7
+ x <- unit(1)
8
+ y <- unit(nil)
9
+
10
+ unit(x+y)
11
+ end
12
+
13
+ maybe.value.should == nil
14
+ end
15
+
16
+ specify "all non-nil results in complete calculation" do
17
+ maybe = Maybe.run do
18
+ x <- unit(1)
19
+ y <- unit(2)
20
+
21
+ unit(x+y)
22
+ end
23
+
24
+ maybe.value.should == 3
25
+ end
26
+ end
@@ -0,0 +1,37 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+ require 'do_notation/monads/array'
3
+ require 'do_notation/monads/maybe'
4
+
5
+ describe "MonadPlus:" do
6
+ specify "mzero >>= f = mzero" do
7
+ Array.mzero.bind{ |x| unit(x+1) }.should == Array.mzero
8
+ Maybe.mzero.bind{ |x| unit(x+1) }.should == Maybe.mzero
9
+ end
10
+
11
+ specify "v >> mzero = mzero" do
12
+ ([1,2,3] >> Array.mzero).should == Array.mzero
13
+ (Maybe.unit(1) >> Maybe.mzero).should == Maybe.mzero
14
+ end
15
+
16
+ specify "mzero `mplus` m = m" do
17
+ Array.mzero.mplus([1,2,3]).should == [1,2,3]
18
+ Maybe.mzero.mplus(Maybe.unit(1)).should == Maybe.unit(1)
19
+ end
20
+
21
+ specify "m `mplus` mzero = m" do
22
+ [1,2,3].mplus(Array.mzero).should == [1,2,3]
23
+ Maybe.unit(1).mplus(Maybe.mzero).should == Maybe.unit(1)
24
+ end
25
+
26
+ specify "guard() prunes the execution tree" do
27
+ array = Array.run do
28
+ x <- [0,1,2,3]
29
+ y <- [0,1,2,3]
30
+ guard(x + y == 3)
31
+
32
+ unit([x,y])
33
+ end
34
+
35
+ array.should == [[0, 3], [1, 2], [2, 1], [3, 0]]
36
+ end
37
+ end
@@ -0,0 +1,46 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+ require 'do_notation/monads/simulations'
3
+
4
+ roll_3d6 = proc do
5
+ d1 <- rand(6)
6
+ d2 <- rand(6)
7
+ d3 <- rand(6)
8
+
9
+ unit(1+d1 + 1+d2 + 1+d3)
10
+ end
11
+
12
+ roll_3d6_b = proc do
13
+ d1 <- rand(6)
14
+ d2 <- rand(6)
15
+ d3 <- rand(6)
16
+
17
+ if [d1, d2, d3].include?(5)
18
+ run do
19
+ d4 <- rand(6)
20
+ unit(1+d1 + 1+d2 + 1+d3 + 1+d4)
21
+ end
22
+ else
23
+ unit(1+d1 + 1+d2 + 1+d3)
24
+ end
25
+ end
26
+
27
+ describe "Simulation" do
28
+ specify "generates correct answers" do
29
+ Simulation.run(&roll_3d6).play.should == 9
30
+ Simulation.run(&roll_3d6_b).play.should == 9
31
+ end
32
+ end
33
+
34
+ describe "Distribution" do
35
+ specify "generates correct answers" do
36
+ Distribution.run(&roll_3d6).play.inspect.should == "[[3, 0.00462962962962963], [4, 0.0138888888888889], [5, 0.0277777777777778], [6, 0.0462962962962963], [7, 0.0694444444444444], [8, 0.0972222222222222], [9, 0.115740740740741], [10, 0.125], [11, 0.125], [12, 0.115740740740741], [13, 0.0972222222222222], [14, 0.0694444444444444], [15, 0.0462962962962963], [16, 0.0277777777777778], [17, 0.0138888888888889], [18, 0.00462962962962963]]"
37
+ Distribution.run(&roll_3d6_b).play.inspect.should == "[[3, 0.00462962962962963], [4, 0.0138888888888889], [5, 0.0277777777777778], [6, 0.0462962962962963], [7, 0.0694444444444444], [8, 0.0833333333333333], [9, 0.0902777777777777], [10, 0.0902777777777778], [11, 0.0833333333333333], [12, 0.0694444444444445], [13, 0.0625000000000001], [14, 0.0601851851851853], [15, 0.0578703703703705], [16, 0.0555555555555557], [17, 0.0532407407407408], [18, 0.0462962962962964], [19, 0.0354938271604938], [20, 0.0239197530864198], [21, 0.0146604938271605], [22, 0.00771604938271605], [23, 0.00308641975308642], [24, 0.000771604938271605]]"
38
+ end
39
+ end
40
+
41
+ describe "Expectation" do
42
+ specify "generates correct answers" do
43
+ (1..21).collect { |x| Expectation.run(&roll_3d6).play(x) }.inspect.should == "[0.0, 0.0, 0.00462962962962963, 0.0138888888888889, 0.0277777777777778, 0.0462962962962963, 0.0694444444444444, 0.0972222222222222, 0.115740740740741, 0.125, 0.125, 0.115740740740741, 0.0972222222222222, 0.0694444444444444, 0.0462962962962963, 0.0277777777777778, 0.0138888888888889, 0.00462962962962963, 0.0, 0.0, 0.0]"
44
+ (1..21).collect { |x| Expectation.run(&roll_3d6_b).play(x) }.inspect.should == "[0.0, 0.0, 0.00462962962962963, 0.0138888888888889, 0.0277777777777778, 0.0462962962962963, 0.0694444444444444, 0.0833333333333333, 0.0902777777777778, 0.0902777777777777, 0.0833333333333333, 0.0694444444444444, 0.0625, 0.0601851851851852, 0.0578703703703704, 0.0555555555555556, 0.0532407407407407, 0.0462962962962963, 0.0354938271604938, 0.0239197530864197, 0.0146604938271605]"
45
+ end
46
+ end
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), %w(.. lib do_notation))
@@ -0,0 +1,66 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+ require 'do_notation/monads/array'
3
+
4
+ describe "Monad.run" do
5
+ specify "should have lexical scope" do
6
+ foo = "cousin"
7
+ bar = "removed"
8
+
9
+ array = Array.run do
10
+ x <- ["first", "second"]
11
+ y <- ["once", "twice"]
12
+
13
+ unit("#{x} #{foo} #{y} #{bar}")
14
+ end
15
+
16
+ array.should == ["first cousin once removed",
17
+ "first cousin twice removed",
18
+ "second cousin once removed",
19
+ "second cousin twice removed"]
20
+ end
21
+
22
+ specify "should be nestable" do
23
+ array = Array.run do
24
+ x <- run do
25
+ a <- ['A','a']
26
+ b <- ['B','b']
27
+
28
+ unit(a+b)
29
+ end
30
+
31
+ y <- run do
32
+ c <- ['C','c']
33
+ d <- ['D','d']
34
+
35
+ unit(c+d)
36
+ end
37
+
38
+ unit(x+y)
39
+ end
40
+
41
+ array.should == ["ABCD", "ABCd", "ABcD", "ABcd",
42
+ "AbCD", "AbCd", "AbcD", "Abcd",
43
+ "aBCD", "aBCd", "aBcD", "aBcd",
44
+ "abCD", "abCd", "abcD", "abcd"]
45
+ end
46
+ end
47
+
48
+ describe 'Monad#>>' do
49
+ specify "should compose two values, discarding the first" do
50
+ ([1] >> [2]).should == [2]
51
+ end
52
+ end
53
+
54
+ describe "Rewriter.pp" do
55
+ specify "should produce correct output" do
56
+ array = [:a, [:b],
57
+ [:c, :d,
58
+ :e]]
59
+
60
+ Rewriter.pp(array).should == <<CODE.strip
61
+ (:a (:b)
62
+ (:c :d
63
+ :e))
64
+ CODE
65
+ end
66
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: aanand-ruby-do-notation
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Aanand Prasad
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-06-20 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: ParseTree
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "0"
23
+ version:
24
+ - !ruby/object:Gem::Dependency
25
+ name: ruby2ruby
26
+ version_requirement:
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: "0"
32
+ version:
33
+ description: Haskell-style monad do-notation for Ruby
34
+ email: aanand.prasad@gmail.com
35
+ executables: []
36
+
37
+ extensions: []
38
+
39
+ extra_rdoc_files:
40
+ - lib/do_notation/monad.rb
41
+ - lib/do_notation/monad_plus.rb
42
+ - lib/do_notation/monads/array.rb
43
+ - lib/do_notation/monads/maybe.rb
44
+ - lib/do_notation/monads/simulations.rb
45
+ - lib/do_notation/rewriter.rb
46
+ - lib/do_notation.rb
47
+ - README.markdown
48
+ files:
49
+ - lib/do_notation/monad.rb
50
+ - lib/do_notation/monad_plus.rb
51
+ - lib/do_notation/monads/array.rb
52
+ - lib/do_notation/monads/maybe.rb
53
+ - lib/do_notation/monads/simulations.rb
54
+ - lib/do_notation/rewriter.rb
55
+ - lib/do_notation.rb
56
+ - README.markdown
57
+ - test/array.rb
58
+ - test/maybe.rb
59
+ - test/monad_plus.rb
60
+ - test/simulations.rb
61
+ - test/spec_helper.rb
62
+ - test/specs.rb
63
+ - Manifest
64
+ - ruby-do-notation.gemspec
65
+ has_rdoc: true
66
+ homepage: http://github.com/aanand/ruby-do-notation/tree/master
67
+ post_install_message:
68
+ rdoc_options:
69
+ - --line-numbers
70
+ - --inline-source
71
+ - --title
72
+ - Ruby-do-notation
73
+ - --main
74
+ - README.markdown
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: "0"
82
+ version:
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: "0"
88
+ version:
89
+ requirements: []
90
+
91
+ rubyforge_project: ruby-do-notation
92
+ rubygems_version: 1.0.1
93
+ signing_key:
94
+ specification_version: 2
95
+ summary: Haskell-style monad do-notation for Ruby
96
+ test_files: []
97
+