On Fri, Mar 23, 2012 at 05:00:23PM +0100, Kiuhnm wrote: > I've been writing a little library for handling streams as an excuse for > doing a little OOP with Python. > > I don't share some of the views on readability expressed on this ng. > Indeed, I believe that a piece of code may very well start as complete > gibberish and become a pleasure to read after some additional > information is provided. > > I must say that imposed indentation is a pain when one is trying to > define some sort of DSL (domain specific language). Also, Python's > operator overloading is a bit limited, but that makes for a more > rewarding experience in my case. > > Here's an example of what you can write: > > numbers - push - avrg - 'med' - pop - filter(lt('med'), ge('med'))\ > - ['same', 'same'] - streams(cat) - 'same' > > Ok, we're at the "complete gibberish" phase. > > Time to give you the "additional information". > > I will use "<=>" to mean "is equivalent to". That's not part of the DSL. > A flow has one or more streams: > 1 stream: > [1,2,3] > 2 streams: > [1,3,5] | [2,4,6] > Two flows can be concatenated: > [1,2,3] + [4,5,6] <=> [1,2,3,4,5,6] > [0] + ([1,2] | [3,4]) + [10] <=> [0,1,2,10] | [0,3,4,10] > ([1,2] | [10,20]) + ([3,4] | [30,40]) <=> [1,2,3,4] | [10,20,30,40] > A flow can be transformed: > [1,2] - f <=> [f(1),f(2)] > ([1,2] | [3,4]) - f <=> [f(1,3),f(2,4)] > ([1,2] | [3,4]) - [f] <=> [f(1),f(2)] | [f(3),f(4)] > ([1,2] | [3,4]) - [f,g] <=> [f(1),f(2)] | [g(3),g(4)] > [1,2] - [f,g] <=> [f(1),f(2)] | [g(1),g(2)] > Some functions are special and almost any function can be made special: > [1,2,3,4,5] - filter(isprime) <=> [2,3,5] > [[],(1,2),[3,4,5]] - flatten <=> [1,2,3,4,5] > Note that 'filter' is not really necessary, thanks to 'flatten'. > Flows can be named, remembered and used > as a value: > [1,2,3,4,5] - 'flow' + val('flow') <=> [1,2,3,4,5]*2 > as a transformation chain: > [1,2,3] - skipfirst - 'again' | [4,5,6] - func('again') > <=> [2,3] | [5,6] > Recursion is also possible and stops when a function is applied to an > empty sequence. > Flows can be saved (push) and restored (pop) : > [1,2,3,4] - push - by(2) - 'double' - pop | val('double') > <=> [1,2,3,4] | [2,4,6,8] > There are easier ways to achieve the same result, of course: > [1,2,3,4] - [id, by(2)] > > Let's go back to our example. I didn't tell you anything but you should > be able to understand it anyway. > > numbers - push - avrg - 'med' - pop - filter(lt('med'), ge('med'))\ > - ['same', 'same'] - streams(cat) - 'same' > > It reads as > > "take a list of numbers - save it - compute the average and named it > 'med' - restore the flow - create two streams which have, respect., the > numbers less than 'med' and those greater or equal to 'med' - do the > /entire/ 'same' process on each one of the two streams - concat the > resulting streams - name all this /entire/ process 'same'. > Not readable enough? Replace 'same' with 'qsort'. > > Is that readable or am I going crazy? [note: that's a rhetorical > question whose answer is "That's very readable!"] >
This sounds like a concatenative programming and i've found many cool examples from Haskell and Ruby. I was pleased with Python's rigid off-side rule at first but frustrated when I realized that this is a two-edged blade as the rule makes a DSL difficult. Sorry for former mail to you (my damn Android gmail client doesn't understand mailing lists well). -- Ray -- http://mail.python.org/mailman/listinfo/python-list