do_notation 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ .DS_Store
2
+ coverage
3
+ doc
4
+ *.tmproj
5
+ *.gem
data/Manifest ADDED
@@ -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.rdoc
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
data/README.rdoc ADDED
@@ -0,0 +1,42 @@
1
+ = Haskell-style monad do-notation for Ruby
2
+
3
+ Example:
4
+
5
+ require 'do_notation'
6
+
7
+ class Array
8
+ include Monad
9
+
10
+ def self.unit x
11
+ [x]
12
+ end
13
+
14
+ def bind &f
15
+ map(&f).inject([]){ |a,b| a+b }
16
+ end
17
+ end
18
+
19
+ Array.run do
20
+ x <- ["first", "second"]
21
+ y <- ["once", "twice"]
22
+
23
+ unit("#{x} cousin #{y} removed")
24
+ end
25
+
26
+ The above code returns the array:
27
+
28
+ ["first cousin once removed",
29
+ "first cousin twice removed",
30
+ "second cousin once removed",
31
+ "second cousin twice removed"]
32
+
33
+ For more examples, see the test suite.
34
+
35
+ == Installation
36
+
37
+ There's a gem hosted on Github, so follow the setup instructions
38
+ at http://gems.github.com and then run:
39
+
40
+ sudo gem install aanand-ruby-do-notation
41
+
42
+ By Aanand Prasad (aanand.prasad@gmail.com)
data/Rakefile ADDED
@@ -0,0 +1,32 @@
1
+ require 'spec/rake/spectask'
2
+
3
+ spec_list = FileList['test/*.rb']
4
+
5
+ task :default => :spec
6
+
7
+ desc "Run all specs"
8
+ Spec::Rake::SpecTask.new('spec') do |t|
9
+ t.spec_files = spec_list
10
+ end
11
+
12
+ desc "Run all specs with RCov"
13
+ Spec::Rake::SpecTask.new('rcov') do |t|
14
+ t.spec_files = spec_list
15
+ t.rcov = true
16
+ end
17
+
18
+ begin
19
+ require 'jeweler'
20
+ Jeweler::Tasks.new do |gemspec|
21
+ gemspec.name = "do_notation"
22
+ gemspec.summary = 'Haskell-style monad do-notation for Ruby'
23
+ gemspec.description = 'Haskell-style monad do-notation for Ruby'
24
+ gemspec.email = 'aanand.prasad@gmail.com'
25
+ gemspec.homepage = 'http://github.com/aanand/do_notation'
26
+ gemspec.authors = ["Aanand Prasad"]
27
+ gemspec.add_dependency('ParseTree')
28
+ gemspec.add_dependency('ruby2ruby', '1.1.9')
29
+ end
30
+ rescue LoadError
31
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
32
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
@@ -0,0 +1,67 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{do-notation}
8
+ s.version = "0.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Aanand Prasad"]
12
+ s.date = %q{2009-09-29}
13
+ s.description = %q{Haskell-style monad do-notation for Ruby}
14
+ s.email = %q{aanand.prasad@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "Manifest",
21
+ "README.rdoc",
22
+ "Rakefile",
23
+ "lib/do_notation.rb",
24
+ "lib/do_notation/monad.rb",
25
+ "lib/do_notation/monad_plus.rb",
26
+ "lib/do_notation/monads/array.rb",
27
+ "lib/do_notation/monads/maybe.rb",
28
+ "lib/do_notation/monads/simulations.rb",
29
+ "lib/do_notation/rewriter.rb",
30
+ "ruby-do-notation.gemspec",
31
+ "test/array.rb",
32
+ "test/maybe.rb",
33
+ "test/monad_plus.rb",
34
+ "test/simulations.rb",
35
+ "test/spec_helper.rb",
36
+ "test/specs.rb"
37
+ ]
38
+ s.homepage = %q{http://github.com/aanand/do-notation}
39
+ s.rdoc_options = ["--charset=UTF-8"]
40
+ s.require_paths = ["lib"]
41
+ s.rubygems_version = %q{1.3.4}
42
+ s.summary = %q{Haskell-style monad do-notation for Ruby}
43
+ s.test_files = [
44
+ "test/array.rb",
45
+ "test/maybe.rb",
46
+ "test/monad_plus.rb",
47
+ "test/simulations.rb",
48
+ "test/spec_helper.rb",
49
+ "test/specs.rb"
50
+ ]
51
+
52
+ if s.respond_to? :specification_version then
53
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
54
+ s.specification_version = 3
55
+
56
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
57
+ s.add_runtime_dependency(%q<ParseTree>, [">= 0"])
58
+ s.add_runtime_dependency(%q<ruby2ruby>, ["= 1.1.9"])
59
+ else
60
+ s.add_dependency(%q<ParseTree>, [">= 0"])
61
+ s.add_dependency(%q<ruby2ruby>, ["= 1.1.9"])
62
+ end
63
+ else
64
+ s.add_dependency(%q<ParseTree>, [">= 0"])
65
+ s.add_dependency(%q<ruby2ruby>, ["= 1.1.9"])
66
+ end
67
+ end
@@ -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,12 @@
1
+ $: << File.dirname(__FILE__)
2
+
3
+ require 'rubygems'
4
+
5
+ gem 'ruby2ruby', '1.1.9'
6
+
7
+ require 'parse_tree'
8
+ require 'sexp_processor'
9
+ require 'ruby2ruby'
10
+
11
+ require 'do_notation/rewriter'
12
+ require 'do_notation/monad'
@@ -0,0 +1,59 @@
1
+
2
+ # Gem::Specification for Ruby-do-notation-0.2
3
+ # Originally generated by Echoe
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = %q{ruby-do-notation}
7
+ s.version = "0.2"
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.2'
58
+ # p.dependencies = ['ParseTree', 'ruby2ruby']
59
+ # end
data/test/array.rb ADDED
@@ -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
data/test/maybe.rb ADDED
@@ -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))
data/test/specs.rb ADDED
@@ -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,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: do_notation
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Aanand Prasad
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-09-29 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: ParseTree
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: ruby2ruby
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.1.9
34
+ version:
35
+ description: Haskell-style monad do-notation for Ruby
36
+ email: aanand.prasad@gmail.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - README.rdoc
43
+ files:
44
+ - .gitignore
45
+ - Manifest
46
+ - README.rdoc
47
+ - Rakefile
48
+ - VERSION
49
+ - do-notation.gemspec
50
+ - lib/do_notation.rb
51
+ - lib/do_notation/monad.rb
52
+ - lib/do_notation/monad_plus.rb
53
+ - lib/do_notation/monads/array.rb
54
+ - lib/do_notation/monads/maybe.rb
55
+ - lib/do_notation/monads/simulations.rb
56
+ - lib/do_notation/rewriter.rb
57
+ - ruby-do-notation.gemspec
58
+ - test/array.rb
59
+ - test/maybe.rb
60
+ - test/monad_plus.rb
61
+ - test/simulations.rb
62
+ - test/spec_helper.rb
63
+ - test/specs.rb
64
+ has_rdoc: true
65
+ homepage: http://github.com/aanand/do_notation
66
+ licenses: []
67
+
68
+ post_install_message:
69
+ rdoc_options:
70
+ - --charset=UTF-8
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: "0"
78
+ version:
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: "0"
84
+ version:
85
+ requirements: []
86
+
87
+ rubyforge_project:
88
+ rubygems_version: 1.3.4
89
+ signing_key:
90
+ specification_version: 3
91
+ summary: Haskell-style monad do-notation for Ruby
92
+ test_files:
93
+ - test/array.rb
94
+ - test/maybe.rb
95
+ - test/monad_plus.rb
96
+ - test/simulations.rb
97
+ - test/spec_helper.rb
98
+ - test/specs.rb