lab419_streams 0.1.0.pre

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,10 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2012 Robert Dober
4
+
5
+ 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:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ 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.
10
+
data/README.md ADDED
@@ -0,0 +1,14 @@
1
+ # Lab419 Streams
2
+
3
+ ## Lazy Evaluation For Lazy Programmers
4
+
5
+
6
+ ### The Integers
7
+
8
+ ```ruby
9
+ integers = cons_stream( 0 ){ binop_stream( :+, integers, 1 ) }
10
+
11
+ integers.head # --> 0
12
+
13
+ integers.tail.take 5 # --> [*1..5]
14
+ ```
@@ -0,0 +1 @@
1
+ require 'lab419/streams/kernel'
@@ -0,0 +1,65 @@
1
+ module Lab419
2
+ module Streams
3
+ module Derived
4
+
5
+ def append *streams
6
+ return __append_to_empty__ streams if empty?
7
+ cons_stream head do
8
+ tail.append( *streams )
9
+ end
10
+ end
11
+
12
+ def filter lbda=nil, &or_blk
13
+ raise ArgumentError, "provide either block or lambda" if !!lbda == !!or_blk
14
+ __filter__ lbda || or_blk
15
+ end
16
+
17
+ # TODO: To a module for streams of streams?
18
+ def flatmap lbda=nil, &or_blk
19
+ raise ArgumentError, "provide either block or lambda" if !!lbda == !!or_blk
20
+ __flatmap__ lbda || or_blk
21
+ end
22
+
23
+ def merge other
24
+ other = other.to_stream unless self.class === other
25
+ Streams::Merger.merge self, other
26
+ end
27
+ def smap lbda=nil, &or_blk
28
+ raise ArgumentError, "provide either block or lambda" if !!lbda == !!or_blk
29
+ __smap__ lbda || or_blk
30
+ end
31
+
32
+ protected
33
+ def __filter__ lbda
34
+ return empty_stream if empty?
35
+ return cons_stream( head ){ tail.__filter__ lbda } if lbda.( head )
36
+ return tail.__filter__ lbda
37
+ end
38
+
39
+ def __flatmap__ lbda
40
+ return empty_stream if empty?
41
+ return tail.__flatmap__ lbda if head.empty?
42
+ cons_stream lbda.( head.first ) do
43
+ cons_stream( head.tail ){ tail }.__flatmap__ lbda
44
+ end
45
+ end
46
+
47
+ def __smap__ lbda
48
+ return empty_stream if empty?
49
+ return cons_stream lbda.( head ) do
50
+ tail.__smap__ lbda
51
+ end
52
+ end
53
+
54
+ private
55
+ def __append_to_empty__ streams
56
+ if streams.empty?
57
+ empty_stream
58
+ else
59
+ streams.first.append( *streams[1..-1] )
60
+ end
61
+ end
62
+
63
+ end # module Derived
64
+ end # module Streams
65
+ end # module Lab419
@@ -0,0 +1,17 @@
1
+ require 'singleton'
2
+
3
+ module Lab419
4
+ class Stream
5
+ IllegalStreamState = Class.new RuntimeError
6
+ class Empty < Lab419::Stream
7
+ include Singleton
8
+ def head; raise IllegalStreamState, "must not call head on empty stream" end
9
+ def tail; raise IllegalStreamState, "must not call tail on empty stream" end
10
+ def empty?; true end
11
+
12
+ private
13
+ def initialize; end
14
+
15
+ end # class Empty
16
+ end # class Stream
17
+ end # module Lab419
@@ -0,0 +1,20 @@
1
+ require 'lab419/streams' # To allow to require this file directly without any precondition
2
+
3
+ module Enumerable
4
+ # TODO: Overload for arrays in order not to create an enumerator for absolutely nothing
5
+ def to_stream
6
+ __to_stream__ to_enum
7
+ end
8
+ private
9
+ def __to_stream__ enum
10
+ cons_stream( enum.next ){ __to_stream__ enum }
11
+ rescue StopIteration
12
+ empty_stream
13
+ end
14
+ end
15
+
16
+ module Kernel
17
+ def finite_stream *args
18
+ args.to_stream
19
+ end
20
+ end # module Kernel
@@ -0,0 +1,19 @@
1
+ module Lab419
2
+ module Streams
3
+ module Merger extend self
4
+ def merge str1, str2
5
+ if str1.empty?
6
+ str2
7
+ elsif str2.empty?
8
+ str1
9
+ else
10
+ cons_stream( str1.head ){
11
+ cons_stream( str2.head ){
12
+ merge str1.tail, str2.tail
13
+ }
14
+ }
15
+ end
16
+ end
17
+ end # module Merger extend self
18
+ end # module Streams
19
+ end # module Lab419
@@ -0,0 +1,16 @@
1
+ require 'lab419/streams'
2
+
3
+ module Kernel
4
+ def integers from = 0
5
+ cons_stream from do
6
+ integers from.succ
7
+ end
8
+ end
9
+ # There are so many possibilities to define odds and evens that it is mind boggeling
10
+ def odds from=1
11
+ integers( from ).filter(&:odd?)
12
+ end
13
+ def evens from=0
14
+ integers( from ).filter(&:even?)
15
+ end
16
+ end # module Kernel
@@ -0,0 +1,27 @@
1
+ require 'lab419/streams/stream'
2
+
3
+ module Kernel
4
+ def binop_stream_const op, lhs_stream, rhs_operand
5
+ return lhs_stream if lhs_stream.empty?
6
+ cons_stream lhs_stream.head.send( op, rhs_operand ) do
7
+ binop_stream_const op, lhs_stream.tail, rhs_operand
8
+ end
9
+ end
10
+
11
+ def binop_streams op, lhs, rhs
12
+ return empty_stream if lhs.empty? || rhs.empty?
13
+ cons_stream lhs.head.send( op, rhs.head ) do
14
+ binop_streams op, lhs.tail, rhs.tail
15
+ end
16
+ end
17
+
18
+ def cons_stream head, &tail
19
+ Lab419::Stream.new head, tail
20
+ end
21
+
22
+ def const_stream const
23
+ cons_stream( const ){ const_stream const }
24
+ end
25
+
26
+ def empty_stream; Lab419::Stream::Empty.instance end
27
+ end # module Kernel
@@ -0,0 +1,18 @@
1
+ module Lab419
2
+ module Streams
3
+ module Operators
4
+ def + otha
5
+ otha is const_stream otha unless self.class === otha
6
+ __plus__ otha
7
+ end
8
+
9
+ protected
10
+ def __plus__ otha
11
+ return empty_stream if empty?
12
+ cons_stream head + otha.head do
13
+ tail.__plus__ otha.tail
14
+ end
15
+ end
16
+ end # module Operators
17
+ end # module Streams
18
+ end # module Lab419
@@ -0,0 +1,69 @@
1
+ require 'lab419/streams/empty'
2
+ require 'lab419/streams/helpers/merger'
3
+ require 'lab419/streams/operators'
4
+ require 'lab419/streams/derived'
5
+
6
+ module Lab419
7
+ class Stream
8
+
9
+ attr_reader :head
10
+
11
+ include Enumerable
12
+ include Lab419::Streams::Operators
13
+ include Lab419::Streams::Derived
14
+
15
+
16
+ def drop n = 1
17
+ x = self
18
+ loop do
19
+ return empty_stream if x.empty?
20
+ return x if n.zero?
21
+ x = x.tail
22
+ n -= 1
23
+ end
24
+ end
25
+
26
+ def each
27
+ x = self
28
+ loop do
29
+ return if x.empty?
30
+ yield x.head.tap{ x = x.tail }
31
+ end
32
+ end
33
+
34
+ def empty?; false end
35
+
36
+ def tail
37
+ @tail.()
38
+ end
39
+
40
+ def take n = 1
41
+ x = self
42
+ n.times.inject [] do | a, _ |
43
+ return a if x.empty?
44
+ a << x.head
45
+ x = x.tail
46
+ a
47
+ end
48
+ end
49
+
50
+ private
51
+ def initialize head, tail
52
+ @head = head
53
+ @tail = memoize tail
54
+ end
55
+
56
+ def memoize lbda
57
+ run = false
58
+ result = nil
59
+ -> do
60
+ if run
61
+ result
62
+ else
63
+ run = true
64
+ result = lbda.()
65
+ end
66
+ end
67
+ end
68
+ end # class Stream
69
+ end # module Lab419
@@ -0,0 +1,5 @@
1
+ module Lab419
2
+ module Streams
3
+ VERSION = "0.1.0.pre"
4
+ end # module Streams
5
+ end # module Lab419
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lab419_streams
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0.pre
5
+ prerelease: 6
6
+ platform: ruby
7
+ authors:
8
+ - Robert Dober
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: ruby-debug19
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '0.11'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '0.11'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.9.2.2
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.9.2.2
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 2.12.0
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 2.12.0
62
+ description: ! "Implemention of streams in the classic sense where a stream is a head
63
+ and a promise to compute the tail.\n Utilities to use streams from enumerables"
64
+ email: robert.dober@gmail.com
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - lib/lab419/streams/enumerable.rb
70
+ - lib/lab419/streams/integers.rb
71
+ - lib/lab419/streams/kernel.rb
72
+ - lib/lab419/streams/version.rb
73
+ - lib/lab419/streams/derived.rb
74
+ - lib/lab419/streams/stream.rb
75
+ - lib/lab419/streams/operators.rb
76
+ - lib/lab419/streams/empty.rb
77
+ - lib/lab419/streams/helpers/merger.rb
78
+ - lib/lab419/streams.rb
79
+ - LICENSE
80
+ - README.md
81
+ homepage: https://github.com/RobertDober/lab419
82
+ licenses:
83
+ - MIT
84
+ post_install_message:
85
+ rdoc_options: []
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: 1.9.2
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ! '>'
98
+ - !ruby/object:Gem::Version
99
+ version: 1.3.1
100
+ requirements: []
101
+ rubyforge_project:
102
+ rubygems_version: 1.8.24
103
+ signing_key:
104
+ specification_version: 3
105
+ summary: Implementing Lazy Evaluation
106
+ test_files: []
107
+ has_rdoc: