Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #22079 > unrolled thread
| Started by | Kiuhnm <kiuhnm03.4t.yahoo.it> |
|---|---|
| First post | 2012-03-23 17:00 +0100 |
| Last post | 2012-03-26 13:45 +0200 |
| Articles | 17 — 7 participants |
Back to article view | Back to comp.lang.python
Stream programming Kiuhnm <kiuhnm03.4t.yahoo.it> - 2012-03-23 17:00 +0100
Re: Stream programming Kiuhnm <kiuhnm03.4t.yahoo.it> - 2012-03-23 17:02 +0100
Re: Stream programming Nathan Rice <nathan.alexander.rice@gmail.com> - 2012-03-23 12:33 -0400
Re: Stream programming Kiuhnm <kiuhnm03.4t.yahoo.it> - 2012-03-23 21:33 +0100
Re: Stream programming Nathan Rice <nathan.alexander.rice@gmail.com> - 2012-03-23 17:18 -0400
Re: Stream programming Kiuhnm <kiuhnm03.4t.yahoo.it> - 2012-03-24 01:26 +0100
Re: Stream programming Ethan Furman <ethan@stoneleaf.us> - 2012-03-23 14:12 -0700
Re: Stream programming Kiuhnm <kiuhnm03.4t.yahoo.it> - 2012-03-24 00:57 +0100
Re: Stream programming MRAB <python@mrabarnett.plus.com> - 2012-03-23 18:00 +0000
Re: Stream programming Nathan Rice <nathan.alexander.rice@gmail.com> - 2012-03-23 15:23 -0400
Re: Stream programming Kiuhnm <kiuhnm03.4t.yahoo.it> - 2012-03-23 21:44 +0100
Re: Stream programming Ray Song <emacsray@gmail.com> - 2012-03-24 07:32 +0800
Re: Stream programming Kiuhnm <kiuhnm03.4t.yahoo.it> - 2012-03-24 01:41 +0100
Re: Stream programming Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-03-24 03:23 +0000
Re: Stream programming Kiuhnm <kiuhnm03.4t.yahoo.it> - 2012-03-24 12:05 +0100
Re: Stream programming Jean-Michel Pichavant <jeanmichel@sequans.com> - 2012-03-26 11:27 +0200
Re: Stream programming Kiuhnm <kiuhnm03.4t.yahoo.it> - 2012-03-26 13:45 +0200
| From | Kiuhnm <kiuhnm03.4t.yahoo.it> |
|---|---|
| Date | 2012-03-23 17:00 +0100 |
| Subject | Stream programming |
| Message-ID | <4f6c9e17$0$1383$4fafbaef@reader2.news.tin.it> |
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!"]
Kiuhnm
[toc] | [next] | [standalone]
| From | Kiuhnm <kiuhnm03.4t.yahoo.it> |
|---|---|
| Date | 2012-03-23 17:02 +0100 |
| Message-ID | <4f6c9ea3$0$1383$4fafbaef@reader2.news.tin.it> |
| In reply to | #22079 |
On 3/23/2012 17:00, 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
Ops... *everything*.
Kiuhnm
[toc] | [prev] | [next] | [standalone]
| From | Nathan Rice <nathan.alexander.rice@gmail.com> |
|---|---|
| Date | 2012-03-23 12:33 -0400 |
| Message-ID | <mailman.934.1332520419.3037.python-list@python.org> |
| In reply to | #22079 |
> 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]
Algebraically, your concatenation rules don't really make sense - your
flows are both distributive and non distributive. You also make the
implicit assumption of an order over streams in a flow, but disregard
the implications of that assumption in some cases. I understand what
you're trying to communicate, so I think you need to be a little more
strict and explicit in your definitions.
> 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)]
Given the examples you pose here, it is clear that you are assuming
that the streams are synchronized in discrete time. Since you do not
provide any mechanism for temporal alignment of streams you are also
assuming every stream will have an element at every time point, the
streams start at the same time and are of the same length. Is this
what you want? These seem like pretty rough simplifying assumptions.
> 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'.
This implies that your transformations again produce flows. You
should explicitly state this.
> Flows can be named, remembered and used
> as a value:
> [1,2,3,4,5] - 'flow' + val('flow') <=> [1,2,3,4,5]*2
Is this a flow with two identical streams, or a flow with one long
stream formed by concatenation?
> 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)]
You are grasping at an algebra here, a sort of calculus of temporal
observations. You need to step back and make it rigorous before you
worry about issues such as a readable syntax.
Nathan
[toc] | [prev] | [next] | [standalone]
| From | Kiuhnm <kiuhnm03.4t.yahoo.it> |
|---|---|
| Date | 2012-03-23 21:33 +0100 |
| Message-ID | <4f6cde28$0$1383$4fafbaef@reader1.news.tin.it> |
| In reply to | #22084 |
On 3/23/2012 17:33, Nathan Rice wrote:
>> 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]
>
> Algebraically, your concatenation rules don't really make sense - your
> flows are both distributive and non distributive.
?
> You also make the
> implicit assumption of an order over streams in a flow, but disregard
> the implications of that assumption in some cases.
?
> I understand what
> you're trying to communicate, so I think you need to be a little more
> strict and explicit in your definitions.
No, I don't think you understand what I meant.
>> 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)]
>
> Given the examples you pose here, it is clear that you are assuming
> that the streams are synchronized in discrete time. Since you do not
> provide any mechanism for temporal alignment of streams you are also
> assuming every stream will have an element at every time point, the
> streams start at the same time and are of the same length. Is this
> what you want?
Yes. I thought that streams as an alternative to functional programming
were widely known.
>> 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'.
>
> This implies that your transformations again produce flows. You
> should explicitly state this.
Isn't that obvious? BTW, those are not rigorous definitions. I thought I
was talking to people who regularly works with streams.
>> Flows can be named, remembered and used
>> as a value:
>> [1,2,3,4,5] - 'flow' + val('flow')<=> [1,2,3,4,5]*2
>
> Is this a flow with two identical streams, or a flow with one long
> stream formed by concatenation?
What does
[1,2,3,4,5]*2
mean in Python?
Those are Python's lists/arrays.
>> 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)]
>
> You are grasping at an algebra here, a sort of calculus of temporal
> observations. You need to step back and make it rigorous before you
> worry about issues such as a readable syntax.
>
> Nathan
I don't agree. Sorry.
Kiuhnm
[toc] | [prev] | [next] | [standalone]
| From | Nathan Rice <nathan.alexander.rice@gmail.com> |
|---|---|
| Date | 2012-03-23 17:18 -0400 |
| Message-ID | <mailman.945.1332537502.3037.python-list@python.org> |
| In reply to | #22095 |
>> I understand what >> you're trying to communicate, so I think you need to be a little more >> strict and explicit in your definitions. > > > No, I don't think you understand what I meant. I don't agree. Sorry. > Yes. I thought that streams as an alternative to functional programming were > widely known. Streams aren't really a paradigm of computation. They're a semantic element of a computational system which cuts across paradigms. If you want to retract that and say you were talking about dataflow programming (which is much larger than streams, and actually has a cohesive definition), I won't hold it against you. Ultimately though, functional programming and dataflow programming are closely linked, the main difference being the use of queues based rather than stacks. > Isn't that obvious? BTW, those are not rigorous definitions. I thought I was talking to people who regularly works with streams. That is the GPU mailing list, down the hall on the left. > Instead of talking of what I wasn't trying to do and, indeed, I didn't do, > you should try to understand what I wanted to do and, in fact, I did. > I'm afraid your cup is too full to understand simple things as the one I > wrote in my OP. Clearly, because I didn't explicitly include the possibility that you are just writing throwaway code with no attempt at development of ideas for the purpose of practicing writing code in the paragraph after the one you quoted. If your goal is to learn to code, instead of posting a message stating that you have a superior way to compose code, you might want to try to solve a problem and ask others their opinion of the structure and techniques in your code.
[toc] | [prev] | [next] | [standalone]
| From | Kiuhnm <kiuhnm03.4t.yahoo.it> |
|---|---|
| Date | 2012-03-24 01:26 +0100 |
| Message-ID | <4f6d14ca$0$1392$4fafbaef@reader1.news.tin.it> |
| In reply to | #22098 |
On 3/23/2012 22:18, Nathan Rice wrote: >>> I understand what >>> you're trying to communicate, so I think you need to be a little more >>> strict and explicit in your definitions. >> >> >> No, I don't think you understand what I meant. > > I don't agree. Sorry. You could just point out those inconsistencies that you found. >> Yes. I thought that streams as an alternative to functional programming were >> widely known. > > Streams aren't really a paradigm of computation. They're a semantic > element of a computational system which cuts across paradigms. If you > want to retract that and say you were talking about dataflow > programming (which is much larger than streams, and actually has a > cohesive definition), I won't hold it against you. I wasn't talking of dataflow programming. "Flow programming" is much closer to functional programming than dataflow programming is. >> Instead of talking of what I wasn't trying to do and, indeed, I didn't do, >> you should try to understand what I wanted to do and, in fact, I did. >> I'm afraid your cup is too full to understand simple things as the one I >> wrote in my OP. > > Clearly, because I didn't explicitly include the possibility that you > are just writing throwaway code with no attempt at development of > ideas for the purpose of practicing writing code in the paragraph > after the one you quoted. x != 'a' doesn't imply that x == 'b'. > If your goal is to learn to code, instead of posting a message stating > that you have a superior way to compose code, you might want to try to > solve a problem and ask others their opinion of the structure and > techniques in your code. Never said it was superior. We've been talking about readability a lot, haven't we? I was just proposing something different. Kiuhnm
[toc] | [prev] | [next] | [standalone]
| From | Ethan Furman <ethan@stoneleaf.us> |
|---|---|
| Date | 2012-03-23 14:12 -0700 |
| Message-ID | <mailman.946.1332538494.3037.python-list@python.org> |
| In reply to | #22095 |
Kiuhnm wrote: > On 3/23/2012 17:33, Nathan Rice wrote: >> Given the examples you pose here, it is clear that you are assuming >> that the streams are synchronized in discrete time. Since you do not >> provide any mechanism for temporal alignment of streams you are also >> assuming every stream will have an element at every time point, the >> streams start at the same time and are of the same length. Is this >> what you want? > > Yes. I thought that streams as an alternative to functional programming > were widely known. Don't know about widely, but I can say I am unfamiliar with the way you are using them. >> This implies that your transformations again produce flows. You >> should explicitly state this. > > Isn't that obvious? BTW, those are not rigorous definitions. I thought I > was talking to people who regularly works with streams. Why would you think that? This list is composed of all types that use Python. I've seen occasional discussion of functional programming, but I've only seen anything this confusing maybe twice before... granted, I don't read *everything*, but I do read quite a bit -- especially the stuff that looks like it might be interesting... like "stream programming", for example. ;) After the discussion I've seen so far, I still have no idea how I would use your code or what it's good for. ~Ethan~
[toc] | [prev] | [next] | [standalone]
| From | Kiuhnm <kiuhnm03.4t.yahoo.it> |
|---|---|
| Date | 2012-03-24 00:57 +0100 |
| Message-ID | <4f6d0de7$0$1384$4fafbaef@reader1.news.tin.it> |
| In reply to | #22099 |
On 3/23/2012 22:12, Ethan Furman wrote: > Kiuhnm wrote: >> On 3/23/2012 17:33, Nathan Rice wrote: >>> Given the examples you pose here, it is clear that you are assuming >>> that the streams are synchronized in discrete time. Since you do not >>> provide any mechanism for temporal alignment of streams you are also >>> assuming every stream will have an element at every time point, the >>> streams start at the same time and are of the same length. Is this >>> what you want? >> >> Yes. I thought that streams as an alternative to functional >> programming were widely known. > > Don't know about widely, but I can say I am unfamiliar with the way you > are using them. That's good! It means I'm saying something new (and, hopefully, interesting). >>> This implies that your transformations again produce flows. You >>> should explicitly state this. >> >> Isn't that obvious? BTW, those are not rigorous definitions. I thought >> I was talking to people who regularly works with streams. > > Why would you think that? This list is composed of all types that use > Python. I've seen occasional discussion of functional programming, but > I've only seen anything this confusing maybe twice before... granted, I > don't read *everything*, but I do read quite a bit -- especially the > stuff that looks like it might be interesting... like "stream > programming", for example. ;) > > > After the discussion I've seen so far, I still have no idea how I would > use your code or what it's good for. The idea is simple. Flows or streams let you be more declarative without being too functional :) In imperative progamming you write statements or commands. In functional programming (FP) you write expressions. In streaming programming (SP) you create flows. Basically, if in FP you write h9(h8(h7(.....(h1)....))) in SP you write h1-h2-h3-...-h9 which I greatly prefer because that's the way I think. I think that SP could be an interesting alternative to FP (in ten years, maybe). Mine was just a little experiment. Kiuhnm
[toc] | [prev] | [next] | [standalone]
| From | MRAB <python@mrabarnett.plus.com> |
|---|---|
| Date | 2012-03-23 18:00 +0000 |
| Message-ID | <mailman.941.1332525634.3037.python-list@python.org> |
| In reply to | #22079 |
On 23/03/2012 16:33, Nathan Rice wrote:
>> 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]
>
> Algebraically, your concatenation rules don't really make sense - your
> flows are both distributive and non distributive. You also make the
> implicit assumption of an order over streams in a flow, but disregard
> the implications of that assumption in some cases. I understand what
> you're trying to communicate, so I think you need to be a little more
> strict and explicit in your definitions.
>
When concatenating, either there are the same number of streams, or one
of them is a single stream which is duplicated.
Therefore, in this example:
[0] + ([1, 2] | [3, 4])
you're concatenating a single stream with a pair, so the single stream
is duplicated:
([0] | [0]) + ([1, 2] | [3, 4])
and then they can be concatenated:
([0, 1, 2] | [0, 3, 4])
However, this:
([0, 1] | [2, 3]) + ([4, 5] | [6, 7] | [8, 9])
won't work.
[toc] | [prev] | [next] | [standalone]
| From | Nathan Rice <nathan.alexander.rice@gmail.com> |
|---|---|
| Date | 2012-03-23 15:23 -0400 |
| Message-ID | <mailman.943.1332530583.3037.python-list@python.org> |
| In reply to | #22079 |
>>> 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] >> >> >> Algebraically, your concatenation rules don't really make sense - your >> flows are both distributive and non distributive. You also make the >> implicit assumption of an order over streams in a flow, but disregard >> the implications of that assumption in some cases. I understand what >> you're trying to communicate, so I think you need to be a little more >> strict and explicit in your definitions. >> > When concatenating, either there are the same number of streams, or one > of them is a single stream which is duplicated. > > Therefore, in this example: > > [0] + ([1, 2] | [3, 4]) > > you're concatenating a single stream with a pair, so the single stream > is duplicated: > > ([0] | [0]) + ([1, 2] | [3, 4]) > > and then they can be concatenated: > > ([0, 1, 2] | [0, 3, 4]) > > However, this: > > ([0, 1] | [2, 3]) + ([4, 5] | [6, 7] | [8, 9]) > > won't work. I understand how he wants the system to work in this case; my point was that it isn't consistent. He stated flows can be concatenated, so [0] is just a flow of a single stream. Because he clearly intends that streams in a flow are ordered, that indicates that he wants some sort of algebraic module. He could get close if he can extend a stream to meet the requirements of a ring, then a flow would be a module over the ring of streams. The problem he is going to run into is that operations on streams as he defines them are not commutative. Identity elements for the two binary operations are also not immediately obvious to me. He could just be smart and use the pi calculus, it is rigorously developed and can model his desired behavior, if he reformulates it slightly. Another option is just to give up on being rigorous. Given the abstract treatment he attempted I would be disappointed, but if his only goal is to get practice writing code and he isn't interested in exploring the conceptual space of the problem domain it would be the right decision.
[toc] | [prev] | [next] | [standalone]
| From | Kiuhnm <kiuhnm03.4t.yahoo.it> |
|---|---|
| Date | 2012-03-23 21:44 +0100 |
| Message-ID | <4f6ce0ab$0$1384$4fafbaef@reader1.news.tin.it> |
| In reply to | #22094 |
On 3/23/2012 20:23, Nathan Rice wrote: >>>> 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] >>> >>> >>> Algebraically, your concatenation rules don't really make sense - your >>> flows are both distributive and non distributive. You also make the >>> implicit assumption of an order over streams in a flow, but disregard >>> the implications of that assumption in some cases. I understand what >>> you're trying to communicate, so I think you need to be a little more >>> strict and explicit in your definitions. >>> >> When concatenating, either there are the same number of streams, or one >> of them is a single stream which is duplicated. >> >> Therefore, in this example: >> >> [0] + ([1, 2] | [3, 4]) >> >> you're concatenating a single stream with a pair, so the single stream >> is duplicated: >> >> ([0] | [0]) + ([1, 2] | [3, 4]) >> >> and then they can be concatenated: >> >> ([0, 1, 2] | [0, 3, 4]) >> >> However, this: >> >> ([0, 1] | [2, 3]) + ([4, 5] | [6, 7] | [8, 9]) >> >> won't work. > > I understand how he wants the system to work in this case; my point > was that it isn't consistent. > > He stated flows can be concatenated, so [0] is just a flow of a single > stream. Because he clearly intends that streams in a flow are > ordered, that indicates that he wants some sort of algebraic module. > He could get close if he can extend a stream to meet the requirements > of a ring, then a flow would be a module over the ring of streams. > The problem he is going to run into is that operations on streams as > he defines them are not commutative. Identity elements for the two > binary operations are also not immediately obvious to me. Instead of talking of what I wasn't trying to do and, indeed, I didn't do, you should try to understand what I wanted to do and, in fact, I did. I'm afraid your cup is too full to understand simple things as the one I wrote in my OP. Kiuhnm
[toc] | [prev] | [next] | [standalone]
| From | Ray Song <emacsray@gmail.com> |
|---|---|
| Date | 2012-03-24 07:32 +0800 |
| Message-ID | <mailman.947.1332545570.3037.python-list@python.org> |
| In reply to | #22079 |
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
[toc] | [prev] | [next] | [standalone]
| From | Kiuhnm <kiuhnm03.4t.yahoo.it> |
|---|---|
| Date | 2012-03-24 01:41 +0100 |
| Message-ID | <4f6d1841$0$1381$4fafbaef@reader1.news.tin.it> |
| In reply to | #22103 |
On 3/24/2012 0:32, Ray Song wrote:
> 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.
Yes, there is that. I also noticed that I couldn't use the comparison
operators the way I liked.
Precedence is also an issue. I had to use '+' and '-' instead of '+' and
'>>' or '>' because of that. I didn't want to introduce extra parentheses.
> Sorry for former mail to you (my damn Android gmail client doesn't
> understand mailing lists well).
Don't worry, my email address is invalid!
Kiuhnm
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2012-03-24 03:23 +0000 |
| Message-ID | <4f6d3e3f$0$29981$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #22079 |
On Fri, 23 Mar 2012 17:00:23 +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.
[...]
> 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".
There are multiple problems with your DSL. Having read your explanation,
and subsequent posts, I think I understand the data model, but the syntax
itself is not very good and far from readable. It is just too hard to
reason about the code.
Your syntax conflicts with established, far more common, use of the same
syntax: you use - to mean "call a function" and | to join two or more
streams into a flow.
You also use () for calling functions, and the difference between - and
() isn't clear. So a mystery there -- your DSL seems to have different
function syntax, depending on... what?
The semantics are unclear even after your examples. To understand your
syntax, you give examples, but to understand the examples, the reader
needs to understand the syntax. That suggests that the semantics are
unclear even in your own mind, or at least too difficult to explain in
simple examples.
Take this example:
> 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]
What the hell does that mean? The reader initially doesn't know what
*any* of push, by(2), pop or val('double') means. All they see is an
obfuscated series of calls that starts with a stream as input, makes a
copy of it, and doubles the entries in the copy: you make FIVE function
calls to perform TWO conceptual operations. So the reader can't even map
a function call to a result.
With careful thought and further explanations from you, the reader (me)
eventually gets a mental model here. Your DSL has a single input which is
pipelined through a series of function calls by the - operator, plus a
separate stack. (I initially thought that, like Forth, your DSL was stack
based. But it isn't, is it?)
It seems to me that the - operator is only needed as syntactic sugar to
avoid using reverse Polish notation and an implicit stack. Instead of the
Forth-like:
[1,2,3,4] dup 2 *
your DSL has an explicit stack, and an explicit - operator to call a
function. Presumably "[1,2] push" would be a syntax error.
I think this is a good example of an inferior syntax. Contrast your:
[1,2,3,4] - push - by(2) - 'double' - pop | val('double')
with the equivalent RPL:
[1,2,3,4] dup 2 *
Now *that* is a pleasure to read, once you wrap your head around reverse
Polish notation and the concept of a stack. Which you need in your DSL
anyway, to understand push and pop.
You say that this is an "easier way to get the same result":
[1,2,3,4] - [id, by(2)]
but it isn't, is it? The more complex example above ends up with two
streams joined in a single flow:
[1,2,3,4]|[2,4,6,8]
whereas the shorter version using the magic "id" gives you a single
stream containing nested streams:
[[1,2,3,4], [2,4,6,8]]
So, how could you make this more readable?
* Don't fight the reader's expectations. If they've programmed in Unix
shells, they expect | as the pipelining operator. If they haven't, they
probably will find >> easy to read as a dataflow operator. Either way,
they're probably used to seeing a|b as meaning "or" (as in "this stream,
or this stream") rather than the way you seem to be using it ("this
stream, and this stream").
Here's my first attempt at improved syntax that doesn't fight the user:
[1,2,3,4] >> push >> by(2) >> 'double' >> pop & val('double')
"push" and "pop" are poor choices of words. Push does not actually push
its input onto the stack, which would leave the input stream empty. It
makes a copy. You explain what they do:
"Flows can be saved (push) and restored (pop)"
so why not just use SAVE and RESTORE as your functions? Or if they're too
verbose, STO and RCL, or my preference, store and recall.
[1,2,3,4] >> store >> by(2) >> 'double' >> recall & val('double')
I'm still not happy with & for the join operator. I think that the use of
+ for concatenate and & for join is just one of those arbitrary choices
that the user will have to learn. Although I'm tempted to try using a
colon instead.
[1,2,3]:[4,5,6]
would be a flow with two streams.
I don't like the syntax for defining and using names. Here's a random
thought:
[1,2,3,4] >> store >> by(2) >> @double >> recall & double
Use @name to store to a name, and the name alone to retrieve from it. But
I haven't given this too much thought, so it too might suck.
Some other problems with your DSL:
> A flow can be transformed:
> [1,2] - f <=> [f(1),f(2)]
but that's not consistently true. For instance:
[1,2] - push <=/=> [push(1), push(2)]
So the reader needs to know all the semantics of the particular function
f before being able to reason about the flow. Your DSL displays magic
behaviour, which is bad and makes it hard to read the code because the
reader may not know which functions are magic and which are not.
> 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]
You say that as if it were a good thing.
--
Steven
[toc] | [prev] | [next] | [standalone]
| From | Kiuhnm <kiuhnm03.4t.yahoo.it> |
|---|---|
| Date | 2012-03-24 12:05 +0100 |
| Message-ID | <4f6daa78$0$1377$4fafbaef@reader2.news.tin.it> |
| In reply to | #22110 |
On 3/24/2012 4:23, Steven D'Aprano wrote:
> On Fri, 23 Mar 2012 17:00:23 +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.
> [...]
>> 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".
>
> There are multiple problems with your DSL. Having read your explanation,
> and subsequent posts, I think I understand the data model, but the syntax
> itself is not very good and far from readable. It is just too hard to
> reason about the code.
>
> Your syntax conflicts with established, far more common, use of the same
> syntax: you use - to mean "call a function" and | to join two or more
> streams into a flow.
>
> You also use () for calling functions, and the difference between - and
> () isn't clear. So a mystery there -- your DSL seems to have different
> function syntax, depending on... what?
>
> The semantics are unclear even after your examples. To understand your
> syntax, you give examples, but to understand the examples, the reader
> needs to understand the syntax. That suggests that the semantics are
> unclear even in your own mind, or at least too difficult to explain in
> simple examples.
>
> Take this example:
>
>> 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]
>
> What the hell does that mean? The reader initially doesn't know what
> *any* of push, by(2), pop or val('double') means. All they see is an
> obfuscated series of calls that starts with a stream as input, makes a
> copy of it, and doubles the entries in the copy: you make FIVE function
> calls to perform TWO conceptual operations. So the reader can't even map
> a function call to a result.
>
> With careful thought and further explanations from you, the reader (me)
> eventually gets a mental model here. Your DSL has a single input which is
> pipelined through a series of function calls by the - operator, plus a
> separate stack. (I initially thought that, like Forth, your DSL was stack
> based. But it isn't, is it?)
>
> It seems to me that the - operator is only needed as syntactic sugar to
> avoid using reverse Polish notation and an implicit stack. Instead of the
> Forth-like:
>
> [1,2,3,4] dup 2 *
>
> your DSL has an explicit stack, and an explicit - operator to call a
> function. Presumably "[1,2] push" would be a syntax error.
>
> I think this is a good example of an inferior syntax. Contrast your:
>
> [1,2,3,4] - push - by(2) - 'double' - pop | val('double')
>
> with the equivalent RPL:
>
> [1,2,3,4] dup 2 *
I was just explaining how push and pop work.
I also said that
[1,2,3,4] - [id,by(2)]
would be the recommended way to do it.
> Now *that* is a pleasure to read, once you wrap your head around reverse
> Polish notation and the concept of a stack. Which you need in your DSL
> anyway, to understand push and pop.
I don't see why. Push and pop are not needed. They're just handful
mainly to modify a flow, collect a result, and go back to how the flow
was before the push.
It has nothing to do with RPN (which RPL is based on).
> You say that this is an "easier way to get the same result":
>
> [1,2,3,4] - [id, by(2)]
>
> but it isn't, is it? The more complex example above ends up with two
> streams joined in a single flow:
>
> [1,2,3,4]|[2,4,6,8]
>
> whereas the shorter version using the magic "id" gives you a single
> stream containing nested streams:
>
> [[1,2,3,4], [2,4,6,8]]
Says who?
Here are the rules again:
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)]
Read the last line.
What's very interesting, is that [f,g] is an iterable as well, so your
functions can be generated as needed.
> So, how could you make this more readable?
>
> * Don't fight the reader's expectations. If they've programmed in Unix
> shells, they expect | as the pipelining operator. If they haven't, they
> probably will find>> easy to read as a dataflow operator. Either way,
> they're probably used to seeing a|b as meaning "or" (as in "this stream,
> or this stream") rather than the way you seem to be using it ("this
> stream, and this stream").
>
> Here's my first attempt at improved syntax that doesn't fight the user:
>
> [1,2,3,4]>> push>> by(2)>> 'double'>> pop& val('double')
There are problems with your syntax.
Mine:
[...]+[...] - f + [...] - g - h + [...] - i + [...]
Yours:
((([...]+[...] >> f) + [...] >> g >> h) + [...] >> i) + [...]
I first tried to use '<<' and '>>' but '+' and '-' are much better.
> "push" and "pop" are poor choices of words. Push does not actually push
> its input onto the stack, which would leave the input stream empty. It
> makes a copy. You explain what they do:
Why should push move and not copy? In asm and openGL they copy, for
instance.
> "Flows can be saved (push) and restored (pop)"
>
> so why not just use SAVE and RESTORE as your functions? Or if they're too
> verbose, STO and RCL, or my preference, store and recall.
Because that's not what they do.
push and pop actually push and pop, i.e. they can be nested and work as
expected.
> [1,2,3,4]>> store>> by(2)>> 'double'>> recall& val('double')
>
> I'm still not happy with& for the join operator. I think that the use of
> + for concatenate and& for join is just one of those arbitrary choices
> that the user will have to learn. Although I'm tempted to try using a
> colon instead.
>
> [1,2,3]:[4,5,6]
>
> would be a flow with two streams.
I can't see a way to overload ':' in Python. There are also technical
limitations.
> I don't like the syntax for defining and using names. Here's a random
> thought:
>
> [1,2,3,4]>> store>> by(2)>> @double>> recall& double
>
> Use @name to store to a name, and the name alone to retrieve from it. But
> I haven't given this too much thought, so it too might suck.
The problem, again, is Python limitation in defining DSLs.
At this point, one would have to interpret command-strings. I was trying
to avoid an interpreter on an interpreter.
> Some other problems with your DSL:
>
>> A flow can be transformed:
>> [1,2] - f<=> [f(1),f(2)]
>
> but that's not consistently true. For instance:
>
> [1,2] - push<=/=> [push(1), push(2)]
push is a special function (a keyword). It's clear what it does. It's
just an exception to the general rule.
> So the reader needs to know all the semantics of the particular function
> f before being able to reason about the flow.
No, he only has to know special functions. Those are practically keywords.
>> 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]
>
> You say that as if it were a good thing.
It is, because it's never implicit. For instance, isprime is a filter.
flatten is a special builtin function (a keyword).
Kiuhnm
[toc] | [prev] | [next] | [standalone]
| From | Jean-Michel Pichavant <jeanmichel@sequans.com> |
|---|---|
| Date | 2012-03-26 11:27 +0200 |
| Message-ID | <mailman.987.1332754047.3037.python-list@python.org> |
| In reply to | #22079 |
Kiuhnm wrote:
> [snip]
>
> 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!"]
>
> Kiuhnm
Here's a rhetorical answer to your question : whatever you're taking, I
want some !
JM
[toc] | [prev] | [next] | [standalone]
| From | Kiuhnm <kiuhnm03.4t.yahoo.it> |
|---|---|
| Date | 2012-03-26 13:45 +0200 |
| Message-ID | <4f7056e8$0$1375$4fafbaef@reader1.news.tin.it> |
| In reply to | #22166 |
On 3/26/2012 11:27, Jean-Michel Pichavant wrote:
> Kiuhnm wrote:
>> [snip]
>>
>> 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!"]
>>
>> Kiuhnm
>
> Here's a rhetorical answer to your question : whatever you're taking, I
> want some !
LOL. I should have titled my post "A new obfuscation technique" then :)
Kiuhnm
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web