Will Pharo ever get the pipe opeator? http://www.reddit.com/r/smalltalk/comments/27k27b/chaining_messages/ /Garth
The pipe operator appears in many languages (F#, Haskell, Elixir, Clojure (threading macro)). It's an elegant way of chaining method/function calls in the presence of additional parameters. The reddit example could be written using a pipe operator |> #('apple' 'peach' 'banana') |> groupedBy: #size |> select: [:each | each size even] |> values |> collect: #asCommaString. /Garth -- View this message in context: http://forum.world.st/Pipe-operator-tp4762106p4762182.html Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
Garth Holland wrote:
The pipe operator appears in many languages (F#, Haskell, Elixir, Clojure (threading macro)). It's an elegant way of chaining method/function calls in the presence of additional parameters. The reddit example could be written using a pipe operator |>
#('apple' 'peach' 'banana') |> groupedBy: #size |> select: [:each | each size even] |> values |> collect: #asCommaString.
/Garth
Ah... so you mean instead of doing this? (((#('apple' 'peach' 'banana') groupedBy: #size ) select: [:each | each size even] ) values ) collect: #asCommaString. Yes. The former does look nice. cheers -ben
Vassili Bykov wrote about the pipe operator in Smalltalk back in 2007: http://blog.3plus4.org/2007/08/30/message-chains/ frank On 8 June 2014 18:20, Garth Holland <steve9571952@hotmail.com> wrote:
The pipe operator appears in many languages (F#, Haskell, Elixir, Clojure (threading macro)). It's an elegant way of chaining method/function calls in the presence of additional parameters. The reddit example could be written using a pipe operator |>
#('apple' 'peach' 'banana') |> groupedBy: #size |> select: [:each | each size even] |> values |> collect: #asCommaString.
/Garth
-- View this message in context: http://forum.world.st/Pipe-operator-tp4762106p4762182.html Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
Hi, I wrote that reddit post. I was curious if anyone came up with something to this. Since then I discovered that Bert Freudenberg created an asPipe method before, that works exactly the same way as mine. And probably asPipe is a better name than chain. The idea of the pipe operator is interesting as well, but I prefer library based solutions. Attila -- View this message in context: http://forum.world.st/Pipe-operator-tp4762106p4762201.html Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
The pipe operator was discussed extensively on the Squeak list back in 2007. http://lists.squeakfoundation.org/pipermail/squeak-dev/2007-August/thread.ht... I count 161 pipe related messages. Judging from the bug report http://bugs.squeak.org/view.php?id=6649 , the Squeak team were reluctant to make changes to the language. OTOH, the pipe operator has become almost essential in languages such as F#, Clojure and Elixir. /Garth -- View this message in context: http://forum.world.st/Pipe-operator-tp4762106p4762202.html Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
On 8 juin 2014, at 19:20, Garth Holland <steve9571952@hotmail.com> wrote:
The pipe operator appears in many languages (F#, Haskell, Elixir, Clojure (threading macro)). It's an elegant way of chaining method/function calls in the presence of additional parameters. The reddit example could be written using a pipe operator |>
#('apple' 'peach' 'banana') |> groupedBy: #size |> select: [:each | each size even] |> values |> collect: #asCommaString.
The pipe operator is implemented as one of the examples of LanguageBox, a tool that permits to scope language extensions (it's a part of Helvetia made by Lucas Renggli). I once thought that the pipe operator could be useful. But now I notice that the main (if not the only) recurrent use case I found is chaining queries on collections. If you have another recurrent use case (that is not purely idiomatic :) ) please let me know. So yes, using the pipe operator make the snippet more readable but still has much inefficient: at each step a new collection is created just to be trashed afterward. Here it's not a problem but not all collections only have 3 elements ;). For me it's a sign that the collection libraries lack a simple abstraction: composable filters (that is, iterators) to make complex queries. We could have collections answering #query that would responds a QueryBuilder object that would understand common enumeration methods, for example: #('apple' 'peach' 'banana') query groupedBy: #size; select: [:each | each size even]; values; collect: #asCommaString. This would return a CollectFilter on a ValuesFilter on a SelectFilter on a GroupedByFilter on the input collection. The QueryBuilder could then answer a message like #endQuery to compute and return the values obtained by the lastly created filter (embedded in a collection that conforms to the input collection's #species). Since it's just a composition of filter objects over the input collection, no useless intermediate collection is created: better performances & less stress on the GC. Of course this idea is acceptable only if they are no other use cases where the pipe operator is a must.
/Garth
-- View this message in context: http://forum.world.st/Pipe-operator-tp4762106p4762182.html Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
Yes, AFIK, the Java 8 stream API works similarly. The query is called stream(), the endQuery is called collect(Collectors.toList()) -- View this message in context: http://forum.world.st/Pipe-operator-tp4762106p4762209.html Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
XStream I think is exactly about it 2014-06-08 22:46 GMT+04:00 Camille Teruel <camille.teruel@gmail.com>:
On 8 juin 2014, at 19:20, Garth Holland <steve9571952@hotmail.com> wrote:
The pipe operator appears in many languages (F#, Haskell, Elixir, Clojure (threading macro)). It's an elegant way of chaining method/function calls in the presence of additional parameters. The reddit example could be written using a pipe operator |>
#('apple' 'peach' 'banana') |> groupedBy: #size |> select: [:each | each size even] |> values |> collect: #asCommaString.
The pipe operator is implemented as one of the examples of LanguageBox, a tool that permits to scope language extensions (it's a part of Helvetia made by Lucas Renggli).
I once thought that the pipe operator could be useful. But now I notice that the main (if not the only) recurrent use case I found is chaining queries on collections. If you have another recurrent use case (that is not purely idiomatic :) ) please let me know.
So yes, using the pipe operator make the snippet more readable but still has much inefficient: at each step a new collection is created just to be trashed afterward. Here it's not a problem but not all collections only have 3 elements ;).
For me it's a sign that the collection libraries lack a simple abstraction: composable filters (that is, iterators) to make complex queries. We could have collections answering #query that would responds a QueryBuilder object that would understand common enumeration methods, for example:
#('apple' 'peach' 'banana') query groupedBy: #size; select: [:each | each size even]; values; collect: #asCommaString.
This would return a CollectFilter on a ValuesFilter on a SelectFilter on a GroupedByFilter on the input collection. The QueryBuilder could then answer a message like #endQuery to compute and return the values obtained by the lastly created filter (embedded in a collection that conforms to the input collection's #species). Since it's just a composition of filter objects over the input collection, no useless intermediate collection is created: better performances & less stress on the GC.
Of course this idea is acceptable only if they are no other use cases where the pipe operator is a must.
/Garth
-- View this message in context:
http://forum.world.st/Pipe-operator-tp4762106p4762182.html
Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
2014-06-08 20:46 GMT+02:00 Camille Teruel <camille.teruel@gmail.com>:
On 8 juin 2014, at 19:20, Garth Holland <steve9571952@hotmail.com> wrote:
The pipe operator appears in many languages (F#, Haskell, Elixir, Clojure (threading macro)). It's an elegant way of chaining method/function calls in the presence of additional parameters. The reddit example could be written using a pipe operator |>
#('apple' 'peach' 'banana') |> groupedBy: #size |> select: [:each | each size even] |> values |> collect: #asCommaString.
The pipe operator is implemented as one of the examples of LanguageBox, a tool that permits to scope language extensions (it's a part of Helvetia made by Lucas Renggli).
I once thought that the pipe operator could be useful. But now I notice that the main (if not the only) recurrent use case I found is chaining queries on collections. If you have another recurrent use case (that is not purely idiomatic :) ) please let me know.
So yes, using the pipe operator make the snippet more readable but still has much inefficient: at each step a new collection is created just to be trashed afterward. Here it's not a problem but not all collections only have 3 elements ;).
Of course, there are lazy implementations for streams and collections... For me it's a sign that the collection libraries lack a simple abstraction:
composable filters (that is, iterators) to make complex queries. We could have collections answering #query that would responds a QueryBuilder object that would understand common enumeration methods, for example:
#('apple' 'peach' 'banana') query groupedBy: #size; select: [:each | each size even]; values; collect: #asCommaString.
This would return a CollectFilter on a ValuesFilter on a SelectFilter on a GroupedByFilter on the input collection. The QueryBuilder could then answer a message like #endQuery to compute and return the values obtained by the lastly created filter (embedded in a collection that conforms to the input collection's #species). Since it's just a composition of filter objects over the input collection, no useless intermediate collection is created: better performances & less stress on the GC.
Of course this idea is acceptable only if they are no other use cases where the pipe operator is a must.
Yes, Michael Lucas Smith proposed selecting: collecting: ... in the thread from 97. At least for Streams that became a real implementation (Xtreams)
/Garth
-- View this message in context:
http://forum.world.st/Pipe-operator-tp4762106p4762182.html
Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
On 8 June 2014 19:46, Camille Teruel <camille.teruel@gmail.com> wrote:
On 8 juin 2014, at 19:20, Garth Holland <steve9571952@hotmail.com> wrote:
The pipe operator appears in many languages (F#, Haskell, Elixir, Clojure (threading macro)). It's an elegant way of chaining method/function calls in the presence of additional parameters. The reddit example could be written using a pipe operator |>
#('apple' 'peach' 'banana') |> groupedBy: #size |> select: [:each | each size even] |> values |> collect: #asCommaString.
The pipe operator is implemented as one of the examples of LanguageBox, a tool that permits to scope language extensions (it's a part of Helvetia made by Lucas Renggli).
I once thought that the pipe operator could be useful. But now I notice that the main (if not the only) recurrent use case I found is chaining queries on collections. If you have another recurrent use case (that is not purely idiomatic :) ) please let me know.
The pipe operator is just a variant of the flip combinator: Object >> >>> aBlock "Obviously just a strawman implementation" ^ aBlock value: self. lets you write 1 >>> [:x | x + 1] >>> [:x | x * 2] >>> [:x | x + 1] which is easier to read than [:x | x + 1] value: ([:x | x * 2] value: ([:x | x + 1] value: 1)) both because you have less ()s and because it reads left->right. (OK, easier for people whose scripts are left->right.) It's so potent an idiom in F# not only because you can remove a bunch of ()s but also because F# automatically curries all functions. It's this - handling keyword selectors - where the problem comes in for Smalltalk. As Vassili Bykov mentions in his post.
So yes, using the pipe operator make the snippet more readable but still has much inefficient: at each step a new collection is created just to be trashed afterward. Here it's not a problem but not all collections only have 3 elements ;).
For me it's a sign that the collection libraries lack a simple abstraction: composable filters (that is, iterators) to make complex queries. We could have collections answering #query that would responds a QueryBuilder object that would understand common enumeration methods, for example:
#('apple' 'peach' 'banana') query groupedBy: #size; select: [:each | each size even]; values; collect: #asCommaString.
This would return a CollectFilter on a ValuesFilter on a SelectFilter on a GroupedByFilter on the input collection. The QueryBuilder could then answer a message like #endQuery to compute and return the values obtained by the lastly created filter (embedded in a collection that conforms to the input collection's #species).
The key part of this example is the use of the Builder pattern to let you use cascades. The equivalent in Xtreams would be as lazy, as performant, but require lots of ()s: (something like:) (((#('apple 'peach' banana') groupingBy: #size) selecting: [:each | each size even]) rest) asCommaString (Your #values is Xtreams' #rest. You could also pull off less than the entire stream with #read:.)
Since it's just a composition of filter objects over the input collection, no useless intermediate collection is created: better performances & less stress on the GC.
Also, using these lazy streams also lets you both unfold and fold without creating intermediate collections: http://www.lshift.net/blog/2012/04/30/hylomorphisms-through-lazy-streams frank
Of course this idea is acceptable only if they are no other use cases where the pipe operator is a must.
/Garth
-- View this message in context: http://forum.world.st/Pipe-operator-tp4762106p4762182.html Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
"Garth" == Garth Holland <steve9571952@hotmail.com> writes:
Garth> The pipe operator appears in many languages (F#, Haskell, Elixir, Clojure Garth> (threading macro)). And Perl6. -- Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095 <merlyn@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/> Perl/Unix consulting, Technical writing, Comedy, etc. etc. Still trying to think of something clever for the fourth line of this .sig
if you are talking about the extension made by nicolas cellier: probably. Stef On 8/6/14 00:10, S. Garth Holland wrote:
Will Pharo ever get the pipe opeator?
http://www.reddit.com/r/smalltalk/comments/27k27b/chaining_messages/
/Garth
What is that extension? Norbert
Am 08.06.2014 um 09:27 schrieb stepharo <stepharo@free.fr>:
if you are talking about the extension made by nicolas cellier: probably.
Stef
On 8/6/14 00:10, S. Garth Holland wrote: Will Pharo ever get the pipe opeator?
http://www.reddit.com/r/smalltalk/comments/27k27b/chaining_messages/
/Garth
2014-06-08 12:12 GMT+02:00 Norbert Hartl <norbert@hartl.name>:
What is that extension?
Norbert
I'm curious too :) I recently proposed to enable caret as a binary selector, maybe there's been a confusion... I remember a discussion about using ;; as pipe "operator" (it's more syntax sugar than operator), in august 2007 or so. But it was not me. http://bugs.squeak.org/view.php?id=6649
Am 08.06.2014 um 09:27 schrieb stepharo <stepharo@free.fr>:
if you are talking about the extension made by nicolas cellier: probably.
Stef
On 8/6/14 00:10, S. Garth Holland wrote:
Will Pharo ever get the pipe opeator?
http://www.reddit.com/r/smalltalk/comments/27k27b/chaining_messages/
/Garth
Norbert
I'm curious too :) I recently proposed to enable caret as a binary selector, maybe there's been a confusion...
:) Yes my brain is overloaded in this moment. I'm doing far too many things at the same time. Not good.
I remember a discussion about using ;; as pipe "operator" (it's more syntax sugar than operator), in august 2007 or so. But it was not me.
http://bugs.squeak.org/view.php?id=6649
Am 08.06.2014 um 09:27 schrieb stepharo <stepharo@free.fr <mailto:stepharo@free.fr>>:
if you are talking about the extension made by nicolas cellier: probably.
Stef
On 8/6/14 00:10, S. Garth Holland wrote:
Will Pharo ever get the pipe opeator?
http://www.reddit.com/r/smalltalk/comments/27k27b/chaining_messages/
/Garth
I think you need to be more specific. The word pipe is misleading and not mentioned in the reddit post. The solution in that post is not an operator but a pattern you can implement easily yourself. To be more monadic like it wouldn't be this like in the example item safeChain recipient; address; street. Here you need to make sure all messages are chained (using the ; in smalltalk is actually chaining) on the proxy. If the proxy does not return the requested value but again a proxy with that value it would come closer. But not sure what you meant. Norbert
Am 08.06.2014 um 00:10 schrieb "S. Garth Holland" <steve9571952@hotmail.com>:
Will Pharo ever get the pipe opeator?
http://www.reddit.com/r/smalltalk/comments/27k27b/chaining_messages/
/Garth
participants (11)
-
Attila Magyar -
Ben Coman -
Camille Teruel -
Denis Kudriashov -
Frank Shearar -
Garth Holland -
merlyn@stonehenge.com -
Nicolas Cellier -
Norbert Hartl -
S. Garth Holland -
stepharo