From: MenTaLguY Date: 2005-12-11T14:48:42+09:00 Subject: [ANN] lazy.rb 0.2 --=-JYVFo2wxEgbQ6hHxPsff Content-Type: text/plain Content-Transfer-Encoding: quoted-printable Now that I'm done asking stupid questions about iterators, it's time for another release of lazy.rb! =3D=3D WHAT IS THIS THING? =3D=3D lazy.rb is a library which provides lazy evaluation for Ruby. It allows you to optimistically defer computations until they are required. These deferred computations are represented by "promises": prom =3D promise { 2 * 3 } p prom #=3D> #> result =3D demand prom p result #=3D> 6 =20 A promise is only evaluated once, after which it becomes essentially indistinguishable from its result object: p prom #=3D> 6 p prom.class #=3D> Fixnum In fact, you can simply use the promise directly and it will be evaluated for you automatically: prom =3D promise { 8 + 1 } num =3D prom * 2 p num #=3D> 18 p prom #=3D> 9 There's one caveat; Ruby always considers promises, evaluated or not, to be true. If you are testing a result for truth, you must unwrap the result with demand. prom =3D promise { false } demand prom # force evaluation p prom #=3D> false puts "wait, it's true?" if prom #=3D> wait, it's true? puts "no, false. much better." \ unless demand( prom ) #=3D> no, false. much better. Conveniently, calling demand on an already evaluated promise (or even on a regular object) is harmless. p demand( 6 ) #=3D> 6 =3D=3D WHAT'S NEW THIS TIME AROUND? =3D=3D Kernel#force has been renamed to Kernel#demand, though Kernel#force still exists as an alias. I'm still wavering on the final name. Feedback is welcomed. I've also incorporated a very nice suggestion from Tom Payne, so that Object#inspect no longer forces the evaluation of a promise. This makes promises much easier to work with in irb. The biggest new feature is an API for lazy streams. Lazy streams are linked lists of deferred computations. Iterating over the list forces its evaluation, cell by cell. They can be used for many purposes, including a substitute for generators or threads. As linked lists, each cell in the stream (Lazy::Cons) has two attributes: first, and rest. first is the value in that cell, and rest is a reference to the tail (remainder) of the list. There is also a Lazy::Stream class, which wraps a lazy stream and implements Enumerable. The API tries to make both imperative and "pure" stream creation easy. =20 For example: # create a stream of lines from stdin stdin_lines =3D Lazy::generate_stream do |tail| line =3D $stdin.gets if line [ line, tail ] else nil end end # create a stream of Fibbonacci numbers def make_fibs( a=3D1, b=3D0 ) Lazy::cons_stream do sum =3D a + b [ sum, make_fibs( b, sum ) ] end end fibs =3D make_fibs You can use them directly, as linked lists: # echo lines from stdin iter =3D stdin_lines while demand( iter ) puts iter.first iter =3D iter.rest end ...or via the Enumerable interface: # print the Fibbonacci numbers up through 100 enum =3D Lazy::Stream.new( fibs ) enum.each do |n| puts n break if n > 100 end The lazy streams API is still experimental and missing some important functionality (take and drop, for example), but it's already useful at this point and I'd like to get some feedback. =3D=3D WHERE CAN I GET IT? =3D=3D I've got a small web site here: http://moonbase.rydia.net/software/lazy.rb/ lazy.rb is available for download as both a tarball and a gem. This is my first real gem, so let me know if you have any problems with it. There's also a link to the API documentation, but sadly nothing in the way of a tutorial yet. I'll eventually also start publishing my git repository. I keep meaning to get around to it... -mental --=-JYVFo2wxEgbQ6hHxPsff Content-Type: application/pgp-signature; name=signature.asc Content-Description: This is a digitally signed message part -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (GNU/Linux) iD8DBQBDm73lcUNIGiXCc4MRApWLAJsEr6+a7Zqv/JYyZL94/7FRSok43gCfVDwm fR64zX0QUQP2jIgvoUkGbNo= =bXhQ -----END PGP SIGNATURE----- --=-JYVFo2wxEgbQ6hHxPsff--