Permalink
Browse files

first commit

  • Loading branch information...
flori committed Jul 25, 2009
0 parents commit 455d18ccae8f6c18daed33d0014fd8bb0cb835cc
Showing with 2,406 additions and 0 deletions.
  1. +3 −0 .gitignore
  2. +56 −0 CHANGES
  3. +340 −0 COPYING
  4. +39 −0 README
  5. +96 −0 Rakefile
  6. +1 −0 VERSION
  7. +121 −0 doc-main.txt
  8. +101 −0 examples/examples.rb
  9. +17 −0 examples/hamming.rb
  10. +34 −0 examples/pi.rb
  11. +17 −0 examples/sieve.rb
  12. +13 −0 install.rb
  13. +23 −0 lazylist.gemspec
  14. +662 −0 lib/lazylist.rb
  15. +125 −0 lib/lazylist/enumerable.rb
  16. +35 −0 lib/lazylist/enumerator_queue.rb
  17. +137 −0 lib/lazylist/list_builder.rb
  18. +61 −0 lib/lazylist/thread_queue.rb
  19. +8 −0 lib/lazylist/version.rb
  20. +4 −0 make_doc.rb
  21. +20 −0 tests/runner.rb
  22. +389 −0 tests/test.rb
  23. +104 −0 tests/test_enumerable.rb
@@ -0,0 +1,3 @@
+*.sw[pon]
+coverage
+pkg
56 CHANGES
@@ -0,0 +1,56 @@
+2009-07-23 * 0.3.2 * Some cleanup.
+ * Build a gemspec file.
+ * Added end_list method to end a lazy list during the
+ evaluation of a filter predicate.
+2007-11-27 * 0.3.1 * Comron Sattari <comron@gmail.com> reported a bug
+ concerning false values in a lazy list. This problem
+ should be corrected now.
+2007-05-05 * 0.3.0 * Major work on the implementation:
+ - Supports list comprehensions for infinite list like
+ Haskell does by offering a simple DSL.
+ - Added cartesian products to LazyList.
+ Many thanks to Reginald Braithwaite <reg@braythwayt.com>
+ for his interesting ideas & email discussion about this
+ topic. Be sure to check out his blog under
+ http://weblog.raganwald.com/, where he writes about all
+ kinds of other interesting stuff.
+ * A nice side effect of the changes necessary for the
+ new implementation is that the first value of a list is
+ not forced until requested. This also causes a bit of
+ space&time waste, but hardware is getting better and
+ cheaper, isn't it?
+ * Now there is more than one Empty object, be careful not to
+ use equal? to compare them. It's better to use LazyList#empty?
+ for this.
+ * Switched from the continuation based ReadQueue to a Thread
+ based one, that should be a bit faster.
+ * Better organization of the file structure.
+ * Added version information.
+2005-12-23 * 0.2.2 * Added append and + (the binary append case) to append lazy
+ lists to each other.
+2005-12-05 * 0.2.1 * Fixed a documentation bug, reported by Gary Wright <at2002@mac.com>.
+ * enable/disable index reference cache added.
+ * LazyList#sublist added to generate sublists that
+ share elements with their "super" lists.
+2005-10-08 * 0.2.0 * Lots of changes (without backwards compatibility):
+ - Now the usual methods from the Ruby Enumerable module
+ should be much better supported.
+ - In general there are more finite lazy lists returned
+ from methods (for example: lazylist[a, b] or
+ lazylist[a..b]) instead of arrays.
+ - mapper, filter and combine methods give an 'obsoleted'
+ warning now, you better use map, select, and zip from
+ now on.
+2005-09-26 * 0.1.3 * Fixed some Ruby 1.9 incompatibilities.
+ * Added default arguments for drop&take.
+ * I've decided to pollute the Kernel module with the #list
+ method. Sorry, if you don't like it. ;)
+2004-09-30 * 0.1.2 * Added combine method.
+ * The ref method now uses a hash to cache return values.
+ This is not what I would still call a list datastructure.
+ It increases memory consumption (as if that would matter
+ anymore), too. But it speeds up things a great deal, if
+ you persist on using indexes into a list.
+ * Rakefile added
+ * Supports Rubygems now
+2003-09-12 * 0.1.1 * Initial Release
340 COPYING

Large diffs are not rendered by default.

Oops, something went wrong.
39 README
@@ -0,0 +1,39 @@
+Installation
+============
+
+Just type into the command line as root:
+
+# ruby install.rb
+
+Or if you prefer to use rake, try:
+
+# rake install
+
+Or if you want to use rubygems just type this and rubygems fetches the gem and
+installs it for you:
+
+# gem install lazylist
+
+Documentation
+=============
+
+The API documentatin of this library is can be produced by typing:
+$ ruby make_doc.rb
+
+Or with rake:
+$ rake doc
+
+You should also look into the files in the examples directory to get an idea
+how this library is used. It is also interesting to examine the tests directory
+for this reason.
+
+Author
+======
+
+Florian Frank <flori@ping.de>
+
+License
+=======
+
+GNU General Public License (GPL), Version 2
+
@@ -0,0 +1,96 @@
+begin
+ require 'rake/gempackagetask'
+rescue LoadError
+end
+require 'rake/clean'
+require 'rbconfig'
+include Config
+
+PKG_NAME = 'lazylist'
+PKG_VERSION = File.read('VERSION').chomp
+PKG_FILES = FileList['**/*'].exclude(/^(doc|CVS|pkg|coverage)/)
+CLEAN.include 'coverage', 'doc'
+
+desc "Installing library"
+task :install do
+ ruby 'install.rb'
+end
+
+desc "Creating documentation"
+task :doc do
+ ruby 'make_doc.rb'
+end
+
+desc "Run unit tests"
+task :test do
+ ruby %{-Ilib tests/runner.rb}
+end
+
+desc "Testing library with coverage"
+task :coverage do
+ sh 'rcov -x tests -Ilib tests/runner.rb'
+end
+
+if defined? Gem
+ spec_src =<<GEM
+# -*- encoding: utf-8 -*-
+Gem::Specification.new do |s|
+ s.name = '#{PKG_NAME}'
+ s.version = '#{PKG_VERSION}'
+ s.summary = "Implementation of lazy lists for Ruby"
+ s.description = ""
+
+ s.add_dependency('dslkit', '~> 0.2')
+
+ s.files = #{PKG_FILES.to_a.sort.inspect}
+
+ s.require_path = 'lib'
+
+ s.has_rdoc = true
+ s.extra_rdoc_files << 'doc-main.txt'
+ s.rdoc_options << '--main' << 'doc-main.txt'
+ s.test_files << 'tests/runner.rb'
+
+ s.author = "Florian Frank"
+ s.email = "flori@ping.de"
+ s.homepage = "http://#{PKG_NAME}.rubyforge.org"
+ s.rubyforge_project = "#{PKG_NAME}"
+ end
+GEM
+
+ desc 'Create a gemspec file'
+ task :gemspec do
+ File.open("#{PKG_NAME}.gemspec", 'w') do |f|
+ f.puts spec_src
+ end
+ end
+
+ spec = eval(spec_src)
+ Rake::GemPackageTask.new(spec) do |pkg|
+ pkg.need_tar = true
+ pkg.package_files += PKG_FILES
+ end
+end
+
+desc m = "Writing version information for #{PKG_VERSION}"
+task :version do
+ puts m
+ File.open(File.join('lib', PKG_NAME, 'version.rb'), 'w') do |v|
+ v.puts <<EOT
+class LazyList
+ # LazyList version
+ VERSION = '#{PKG_VERSION}'
+ VERSION_ARRAY = VERSION.split(/\\./).map { |x| x.to_i } # :nodoc:
+ VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
+ VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
+ VERSION_BUILD = VERSION_ARRAY[2] # :nodoc:
+end
+EOT
+ end
+end
+
+desc "Default"
+task :default => [ :version, :gemspec, :test ]
+
+desc "Prepare a release"
+task :release => [ :clean, :version, :gemspec, :package ]
@@ -0,0 +1 @@
+0.3.2
@@ -0,0 +1,121 @@
+== LazyList - Implementation of lazy lists for Ruby
+
+=== Description
+
+This class implements lazy lists (or streams) for Ruby. Such lists avoid the
+computation of values which aren't needed for some computation. So it's
+possible to define infinite lists with a limited amount of memory. A value
+that hasn't been used yet is calculated on the fly and saved into the list.
+A value which is used for a second time is computed only once and just read
+out of memory for the second usage.
+
+=== Author
+
+Florian Frank mailto:flori@ping.de
+
+=== License
+
+This is free software; you can redistribute it and/or modify it under the
+terms of the GNU General Public License Version 2 as published by the Free
+Software Foundation: www.gnu.org/copyleft/gpl.html
+
+=== Download
+
+The latest version of this library can be downloaded at
+
+* http://rubyforge.org/frs?group_id=394
+
+The homepage of this library is located at
+
+* http://lazylist.rubyforge.org
+
+=== Example
+
+To compute the square numbers with a lazy list you can define one as
+
+ sq = LazyList.tabulate(1) { |x| x * x }
+
+or in the much nicer list builder syntax:
+
+ sq = list { x * x }.where :x => 1..Infinity
+
+Now it's possible to get the first 10 square numbers by calling
+LazyList#take
+
+ sq.take(10)
+ ===>[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
+
+To compute the first 10 square numbers and do something with them you can
+call the each method with:
+
+ sq.each(10) { |x| puts x }
+
+To compute every square number and do something with them you can call the
+"each" method without an argument:
+
+ sq.each { |x| puts x }
+
+Notice that calls to each without an argument will not return if applied to
+infinite lazy lists.
+
+You can also use indices on lazy lists to get the values at a certain range:
+
+ sq[ 0..9 ] or sq[0, 10]
+ ===>[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
+
+To spare memory it's possible to throw away every element after it was
+fetched:
+
+ sq.take!(1) => [1]
+ sq.take!(1) => [4]
+
+Of course it's also possible to compute more complex lists like the Fibonacci
+sequence:
+
+ fib = LazyList.tabulate(0) { |x| x < 2 ? 1 : fib[x-2] + fib[x-1] }
+
+ fib[100] => 573147844013817084101
+computes the 99th Fibonacci number. (We always start with index 0.)
+ fib[101] => 927372692193078999176
+computes the 100th Fibonacci number. The already computed values are reused
+to compute this result. That's a very transparent way to get memoization for
+sequences that require heavy computation.
+
+You can also use the zip method to create fib:
+
+ fib = list(1, 1) { fib.zip(fib.drop) { |a, b| a + b } }
+
+Another way to create the Fibonacci sequence with the build method is this:
+
+ fib = list(1, 1) { build { a + b }.where(:a => fib, :b => fib.drop(1)) }
+
+You can create lazy lists that are based on arbitrary Enumerables, so can for
+example wrap your passwd file in one pretty easily:
+
+ pw = LazyList[ File.new("/etc/passwd") ]
+
+Call grep to find the users root and flori:
+pw.grep /^(root|flori):/ => ["root:x:0:0:...\n",... ]
+
+In this case the whole passwd file is slurped into the memory. If
+you use
+ pw.find { |x| x =~ /^root:/ } => "root:x:0:0:root:/root:/bin/bash\n"
+instead, only every line until the root line is loaded into the memory.
+
+To create more complex lazy lists, you can build them from already existing
+lazy lists.
+
+Natural numbers:
+ naturals = LazyList.from(1)
+
+Odd Numbers > 100:
+ odds = list { x }.where(:x => naturals) { x % 2 === 1 && x > 100 }
+
+Alternative definition of square numbers:
+ squares = build { odds[0, x].inject(0) { |s, y| s + y } }.where :x => naturals
+
+=== References
+
+A very good introduction into lazy lists can be found in the scheme bible
+Structure and Interpretation of Computer Programs (SICP)
+[http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-24.html#%25_sec_3.5]
Oops, something went wrong.

0 comments on commit 455d18c

Please sign in to comment.