alternative do-block syntax proposal

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
19 messages Options
Reply | Threaded
Open this post in threaded view
|

alternative do-block syntax proposal

Tomek Trzeciak
When I first read about the do syntax in Julia I thought it's a neat sugar, but then it seemed a bit too magic to me. What I mean by magic is that
map([A, B, C]) do x
   
if x < 0 && iseven(x)
       
return 0
   
elseif x == 0
       
return 1
   
else
       
return x
   
end
end
this doesn't give any clue to the unversed that the do-block will create an anonymous function and pass it as the first argument to the function call preceding the block. As an alternative consider this:
map((x)->..., [A, B, C]) 
begin
    if x < 0 && iseven(x)
        return 0
    elseif x == 0
        return 1
    else
        return x
    end
end
I think this makes it much easier to guess the meaning of the construct, plus it has the benefit that in this way one could also allow to pass the anonymous as any other argument if desired, not just the first one:
somefunc(A, B, (x,y)->...)
begin
return y, x
end
Note also that the begin keyword doesn't need to be on the same line as the function call as with the do-construct, since there should be no ambiguity in parsing this (the syntax ->... makes it clear that we need to complete the function definition). In principle, one could allow for any scoping block (for, while, let) to be used there, not just begin-end.

Going with this even further, multiple anonymous function arguments could be allowed with each ->... meaning sort of a deferred definition with the next N scoping blocks after the function call implementing the body of each anonymous function in turn, although this might be stretching it too far.

Anyway, I wonder what are your thoughts on this?
Reply | Threaded
Open this post in threaded view
|

Re: alternative do-block syntax proposal

Jameson Nash
This sounds like it could be useful for implementing an alternative to the do/else proposal. I also like how it makes the anonymous function creation a bit more obvious. 


On Friday, July 25, 2014, Tomek Trzeciak <[hidden email]> wrote:
When I first read about the do syntax in Julia I thought it's a neat sugar, but then it seemed a bit too magic to me. What I mean by magic is that
map([A, B, C]) do x
   
if x < 0 && iseven(x)
       
return 0
   
elseif x == 0
       
return 1
   
else
       
return x
   
end
end
this doesn't give any clue to the unversed that the do-block will create an anonymous function and pass it as the first argument to the function call preceding the block. As an alternative consider this:
map((x)->..., [A, B, C]) 
begin
    if x < 0 && iseven(x)
        return 0
    elseif x == 0
        return 1
    else
        return x
    end
end
I think this makes it much easier to guess the meaning of the construct, plus it has the benefit that in this way one could also allow to pass the anonymous as any other argument if desired, not just the first one:
somefunc(A, B, (x,y)->...)
begin
return y, x
end
Note also that the begin keyword doesn't need to be on the same line as the function call as with the do-construct, since there should be no ambiguity in parsing this (the syntax ->... makes it clear that we need to complete the function definition). In principle, one could allow for any scoping block (for, while, let) to be used there, not just begin-end.

Going with this even further, multiple anonymous function arguments could be allowed with each ->... meaning sort of a deferred definition with the next N scoping blocks after the function call implementing the body of each anonymous function in turn, although this might be stretching it too far.

Anyway, I wonder what are your thoughts on this?
Reply | Threaded
Open this post in threaded view
|

Re: alternative do-block syntax proposal

Simon Danisch
In reply to this post by Tomek Trzeciak
Good idea!
I never felt at ease with the do-block syntax...

Am Freitag, 25. Juli 2014 14:13:31 UTC+2 schrieb Tomek Trzeciak:
When I first read about the do syntax in Julia I thought it's a neat sugar, but then it seemed a bit too magic to me. What I mean by magic is that
map([A, B, C]) do x
   
if x < 0 && iseven(x)
       
return 0
   
elseif x == 0
       
return 1
   
else
       
return x
   
end
end
this doesn't give any clue to the unversed that the do-block will create an anonymous function and pass it as the first argument to the function call preceding the block. As an alternative consider this:
map((x)->..., [A, B, C]) 
begin
    if x < 0 && iseven(x)
        return 0
    elseif x == 0
        return 1
    else
        return x
    end
end
I think this makes it much easier to guess the meaning of the construct, plus it has the benefit that in this way one could also allow to pass the anonymous as any other argument if desired, not just the first one:
somefunc(A, B, (x,y)->...)
begin
return y, x
end
Note also that the begin keyword doesn't need to be on the same line as the function call as with the do-construct, since there should be no ambiguity in parsing this (the syntax ->... makes it clear that we need to complete the function definition). In principle, one could allow for any scoping block (for, while, let) to be used there, not just begin-end.

Going with this even further, multiple anonymous function arguments could be allowed with each ->... meaning sort of a deferred definition with the next N scoping blocks after the function call implementing the body of each anonymous function in turn, although this might be stretching it too far.

Anyway, I wonder what are your thoughts on this?
Reply | Threaded
Open this post in threaded view
|

Re: alternative do-block syntax proposal

Lucas Garron
While the ... looks kind of cool, its role feels unnecessarily context-sensitive. What about specifying that we're using a locally created function, but without introducing new syntax inside the map call? The first thing that comes to mind is a Haskell-like where clause:

map(f, [A, B, C]) where f = x->begin
   if x < 0 && iseven(x)
       return 0
   elseif x == 0
       return 1
   else
       return x
   end
end

This resembles the original example very closely.

(You could also expand it to handle multiple local functions, but at that point you'd probably want to take a closer look at how other languages have handled where/let/etc.)

--------

Removing context-sensitivity might expose you to a few more bugs: if you accidentally change your code to:

f x = #already defined
map(f, [A, B, C]) where betterNamedF = (x->begin

then it may still compile and run. If f and betterNamedF are similar, you might not even catch the bug until much later.
I can think of two counter-measures, though:

- Warn the user that betterNamedF wasn't used (this is simpler than looking for unused variables in general, since the valid scope is small and bounded).
- Use a style convention for the name of f, so that incorrect definitions and uses stand out (and a linter could catch it?).






»Lucas Garron


On Sat, Jul 26, 2014 at 7:09 AM, Simon Danisch <[hidden email]> wrote:
Good idea!
I never felt at ease with the do-block syntax...

Am Freitag, 25. Juli 2014 14:13:31 UTC+2 schrieb Tomek Trzeciak:
When I first read about the do syntax in Julia I thought it's a neat sugar, but then it seemed a bit too magic to me. What I mean by magic is that

map([A, B, C]) do x
   
if x < 0 && iseven(x)
       
return 0
   
elseif x == 0
       
return 1
   
else
       
return x
   
end
end
this doesn't give any clue to the unversed that the do-block will create an anonymous function and pass it as the first argument to the function call preceding the block. As an alternative consider this:

map((x)->..., [A, B, C]) 
begin
    if x < 0 && iseven(x)
        return 0
    elseif x == 0
        return 1
    else
        return x
    end
end
I think this makes it much easier to guess the meaning of the construct, plus it has the benefit that in this way one could also allow to pass the anonymous as any other argument if desired, not just the first one:

somefunc(A, B, (x,y)->...)
begin
return y, x
end
Note also that the begin keyword doesn't need to be on the same line as the function call as with the do-construct, since there should be no ambiguity in parsing this (the syntax ->... makes it clear that we need to complete the function definition). In principle, one could allow for any scoping block (for, while, let) to be used there, not just begin-end.

Going with this even further, multiple anonymous function arguments could be allowed with each ->... meaning sort of a deferred definition with the next N scoping blocks after the function call implementing the body of each anonymous function in turn, although this might be stretching it too far.

Anyway, I wonder what are your thoughts on this?

Reply | Threaded
Open this post in threaded view
|

Re: alternative do-block syntax proposal

Ethan Anderes
+1. I don't know Haskell, so that syntax is new to me, but I instantaneously love it.
Reply | Threaded
Open this post in threaded view
|

Re: alternative do-block syntax proposal

Alireza Nejati
In reply to this post by Tomek Trzeciak
That syntax loses anonymity.

You can just as easily define f separately and pass it to the function; no 'where' clause needed.

On Saturday, July 26, 2014 12:13:31 AM UTC+12, Tomek Trzeciak wrote:
When I first read about the do syntax in Julia I thought it's a neat sugar, but then it seemed a bit too magic to me. What I mean by magic is that
map([A, B, C]) do x
   
if x < 0 && iseven(x)
       
return 0
   
elseif x == 0
       
return 1
   
else
       
return x
   
end
end
this doesn't give any clue to the unversed that the do-block will create an anonymous function and pass it as the first argument to the function call preceding the block. As an alternative consider this:
map((x)->..., [A, B, C]) 
begin
    if x < 0 && iseven(x)
        return 0
    elseif x == 0
        return 1
    else
        return x
    end
end
I think this makes it much easier to guess the meaning of the construct, plus it has the benefit that in this way one could also allow to pass the anonymous as any other argument if desired, not just the first one:
somefunc(A, B, (x,y)->...)
begin
return y, x
end
Note also that the begin keyword doesn't need to be on the same line as the function call as with the do-construct, since there should be no ambiguity in parsing this (the syntax ->... makes it clear that we need to complete the function definition). In principle, one could allow for any scoping block (for, while, let) to be used there, not just begin-end.

Going with this even further, multiple anonymous function arguments could be allowed with each ->... meaning sort of a deferred definition with the next N scoping blocks after the function call implementing the body of each anonymous function in turn, although this might be stretching it too far.

Anyway, I wonder what are your thoughts on this?
Reply | Threaded
Open this post in threaded view
|

Re: alternative do-block syntax proposal

Tomas Lycken

I like the alternative syntax! +1 =)

You can just as easily define f separately and pass it to the function; no ‘where’ clause needed.

Yes, of course. That is still an option for map, open et al, but the new syntax still has the advantage of making it very clear exactly where the function is going to be used. I find that when I use anonymous functions in various contexts, it’s usually because I know I won’t be re-using the function anywhere else, and therefore I don’t want to define anything that clutters up the name space. The proposed syntax (both the `(x,y)->...` variant and the `where` clause) still solve that problem, just as well as the current syntax with do blocks.

// T

On Monday, July 28, 2014 1:21:41 AM UTC+2, Alireza Nejati wrote:

That syntax loses anonymity.

You can just as easily define f separately and pass it to the function; no 'where' clause needed.

On Saturday, July 26, 2014 12:13:31 AM UTC+12, Tomek Trzeciak wrote:
When I first read about the do syntax in Julia I thought it's a neat sugar, but then it seemed a bit too magic to me. What I mean by magic is that
map([A, B, C]) do x
   
if x < 0 && iseven(x)
       
return 0
   
elseif x == 0
       
return 1
   
else
       
return x
   
end
end
this doesn't give any clue to the unversed that the do-block will create an anonymous function and pass it as the first argument to the function call preceding the block. As an alternative consider this:
map((x)->..., [A, B, C]) 
begin
    if x < 0 && iseven(x)
        return 0
    elseif x == 0
        return 1
    else
        return x
    end
end
I think this makes it much easier to guess the meaning of the construct, plus it has the benefit that in this way one could also allow to pass the anonymous as any other argument if desired, not just the first one:
somefunc(A, B, (x,y)->...)
begin
return y, x
end
Note also that the begin keyword doesn't need to be on the same line as the function call as with the do-construct, since there should be no ambiguity in parsing this (the syntax ->... makes it clear that we need to complete the function definition). In principle, one could allow for any scoping block (for, while, let) to be used there, not just begin-end.

Going with this even further, multiple anonymous function arguments could be allowed with each ->... meaning sort of a deferred definition with the next N scoping blocks after the function call implementing the body of each anonymous function in turn, although this might be stretching it too far.

Anyway, I wonder what are your thoughts on this?

Reply | Threaded
Open this post in threaded view
|

Re: alternative do-block syntax proposal

Mike Innes
Since no one else has, I'll chime in in support of the current do block. If anything the proposal seems less intuitive/elegant to me.

The where block is nicer but a new keyword/syntax is going to need a pretty compelling reason to exist, and in this case you can simply write:

function f(x)
  # code...
end
map(f, 1:10)

Within a lexical scope (let block, function body, whatever) this will create an anonymous function rather than cluttering the global namespace. It also has the advantage that you can use multiple dispatch:

function test(xs)
  f(x::Int) = :int
  f(x::Real) = :real
  map(f, xs)
end

This is more flexible and IMO clearer, so long story short I think a major change in this area will be unlikely.


On 29 July 2014 09:42, Tomas Lycken <[hidden email]> wrote:

I like the alternative syntax! +1 =)

You can just as easily define f separately and pass it to the function; no ‘where’ clause needed.

Yes, of course. That is still an option for map, open et al, but the new syntax still has the advantage of making it very clear exactly where the function is going to be used. I find that when I use anonymous functions in various contexts, it’s usually because I know I won’t be re-using the function anywhere else, and therefore I don’t want to define anything that clutters up the name space. The proposed syntax (both the `(x,y)->...` variant and the `where` clause) still solve that problem, just as well as the current syntax with do blocks.

// T

On Monday, July 28, 2014 1:21:41 AM UTC+2, Alireza Nejati wrote:

That syntax loses anonymity.

You can just as easily define f separately and pass it to the function; no 'where' clause needed.

On Saturday, July 26, 2014 12:13:31 AM UTC+12, Tomek Trzeciak wrote:
When I first read about the do syntax in Julia I thought it's a neat sugar, but then it seemed a bit too magic to me. What I mean by magic is that

map([A, B, C]) do x
   
if x < 0 && iseven(x)
       
return 0
   
elseif x == 0
       
return 1
   
else
       
return x
   
end
end
this doesn't give any clue to the unversed that the do-block will create an anonymous function and pass it as the first argument to the function call preceding the block. As an alternative consider this:

map((x)->..., [A, B, C]) 
begin
    if x < 0 && iseven(x)
        return 0
    elseif x == 0
        return 1
    else
        return x
    end
end
I think this makes it much easier to guess the meaning of the construct, plus it has the benefit that in this way one could also allow to pass the anonymous as any other argument if desired, not just the first one:

somefunc(A, B, (x,y)->...)
begin
return y, x
end
Note also that the begin keyword doesn't need to be on the same line as the function call as with the do-construct, since there should be no ambiguity in parsing this (the syntax ->... makes it clear that we need to complete the function definition). In principle, one could allow for any scoping block (for, while, let) to be used there, not just begin-end.

Going with this even further, multiple anonymous function arguments could be allowed with each ->... meaning sort of a deferred definition with the next N scoping blocks after the function call implementing the body of each anonymous function in turn, although this might be stretching it too far.

Anyway, I wonder what are your thoughts on this?


Reply | Threaded
Open this post in threaded view
|

Re: alternative do-block syntax proposal

Stefan Karpinski
To me the major driver for some variation on the current syntax is wanting to chain calls via the |> operator or something like it. I.e. something like this:

v |> f |> 1+_ |> sort(_, rev=true)

This is somewhat related to the idea of having an even terser anonymous function syntax.


On Tue, Jul 29, 2014 at 5:22 AM, Mike Innes <[hidden email]> wrote:
Since no one else has, I'll chime in in support of the current do block. If anything the proposal seems less intuitive/elegant to me.

The where block is nicer but a new keyword/syntax is going to need a pretty compelling reason to exist, and in this case you can simply write:

function f(x)
  # code...
end
map(f, 1:10)

Within a lexical scope (let block, function body, whatever) this will create an anonymous function rather than cluttering the global namespace. It also has the advantage that you can use multiple dispatch:

function test(xs)
  f(x::Int) = :int
  f(x::Real) = :real
  map(f, xs)
end

This is more flexible and IMO clearer, so long story short I think a major change in this area will be unlikely.


On 29 July 2014 09:42, Tomas Lycken <[hidden email]> wrote:

I like the alternative syntax! +1 =)

You can just as easily define f separately and pass it to the function; no ‘where’ clause needed.

Yes, of course. That is still an option for map, open et al, but the new syntax still has the advantage of making it very clear exactly where the function is going to be used. I find that when I use anonymous functions in various contexts, it’s usually because I know I won’t be re-using the function anywhere else, and therefore I don’t want to define anything that clutters up the name space. The proposed syntax (both the `(x,y)->...` variant and the `where` clause) still solve that problem, just as well as the current syntax with do blocks.

// T

On Monday, July 28, 2014 1:21:41 AM UTC+2, Alireza Nejati wrote:

That syntax loses anonymity.

You can just as easily define f separately and pass it to the function; no 'where' clause needed.

On Saturday, July 26, 2014 12:13:31 AM UTC+12, Tomek Trzeciak wrote:
When I first read about the do syntax in Julia I thought it's a neat sugar, but then it seemed a bit too magic to me. What I mean by magic is that


map([A, B, C]) do x
   
if x < 0 && iseven(x)
       
return 0
   
elseif x == 0
       
return 1
   
else
       
return x
   
end
end
this doesn't give any clue to the unversed that the do-block will create an anonymous function and pass it as the first argument to the function call preceding the block. As an alternative consider this:


map((x)->..., [A, B, C]) 
begin
    if x < 0 && iseven(x)
        return 0
    elseif x == 0
        return 1
    else
        return x
    end
end
I think this makes it much easier to guess the meaning of the construct, plus it has the benefit that in this way one could also allow to pass the anonymous as any other argument if desired, not just the first one:


somefunc(A, B, (x,y)->...)
begin
return y, x
end
Note also that the begin keyword doesn't need to be on the same line as the function call as with the do-construct, since there should be no ambiguity in parsing this (the syntax ->... makes it clear that we need to complete the function definition). In principle, one could allow for any scoping block (for, while, let) to be used there, not just begin-end.

Going with this even further, multiple anonymous function arguments could be allowed with each ->... meaning sort of a deferred definition with the next N scoping blocks after the function call implementing the body of each anonymous function in turn, although this might be stretching it too far.

Anyway, I wonder what are your thoughts on this?



Reply | Threaded
Open this post in threaded view
|

Re: alternative do-block syntax proposal

Ethan Anderes

That is a cool suggestion. Would you also be able to do something like this

remotecall(2, _, args...) do x
 # blah
end

If so, it would accomplish what the where syntax was trying to do.

On Tuesday, July 29, 2014 7:45:44 AM UTC-7, Stefan Karpinski wrote:

To me the major driver for some variation on the current syntax is wanting to chain calls via the |> operator or something like it. I.e. something like this:

v |> f |> 1+_ |> sort(_, rev=true)

This is somewhat related to the idea of having an even terser anonymous function syntax.


On Tue, Jul 29, 2014 at 5:22 AM, Mike Innes <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="gvpMZ4bCvyIJ">mike.j...@...> wrote:
Since no one else has, I'll chime in in support of the current do block. If anything the proposal seems less intuitive/elegant to me.

The where block is nicer but a new keyword/syntax is going to need a pretty compelling reason to exist, and in this case you can simply write:

function f(x)
  # code...
end
map(f, 1:10)

Within a lexical scope (let block, function body, whatever) this will create an anonymous function rather than cluttering the global namespace. It also has the advantage that you can use multiple dispatch:

function test(xs)
  f(x::Int) = :int
  f(x::Real) = :real
  map(f, xs)
end

This is more flexible and IMO clearer, so long story short I think a major change in this area will be unlikely.


On 29 July 2014 09:42, Tomas Lycken <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="gvpMZ4bCvyIJ">tomas....@...> wrote:

I like the alternative syntax! +1 =)

You can just as easily define f separately and pass it to the function; no ‘where’ clause needed.

Yes, of course. That is still an option for map, open et al, but the new syntax still has the advantage of making it very clear exactly where the function is going to be used. I find that when I use anonymous functions in various contexts, it’s usually because I know I won’t be re-using the function anywhere else, and therefore I don’t want to define anything that clutters up the name space. The proposed syntax (both the `(x,y)->...` variant and the `where` clause) still solve that problem, just as well as the current syntax with do blocks.

// T

On Monday, July 28, 2014 1:21:41 AM UTC+2, Alireza Nejati wrote:

That syntax loses anonymity.

You can just as easily define f separately and pass it to the function; no 'where' clause needed.

On Saturday, July 26, 2014 12:13:31 AM UTC+12, Tomek Trzeciak wrote:
When I first read about the do syntax in Julia I thought it's a neat sugar, but then it seemed a bit too magic to me. What I mean by magic is that
map([A, B, C]) do x
   
if x < 0 && iseven(x)
       
return 0
   
elseif x == 0
       
return 1
   
else
       
return x
   
end
end
this doesn't give any clue to the unversed that the do-block will create an anonymous function and pass it as the first argument to the function call preceding the block. As an alternative consider this:
map((x)->..., [A, B, C]) 
begin
    if x < 0 && iseven(x)
        return 0
    elseif x == 0
        return 1
    else
        return x
    end
end
I think this makes it much easier to guess the meaning of the construct, plus it has the benefit that in this way one could also allow to pass the anonymous as any other argument if desired, not just the first one:
somefunc(A, B, (x,y)->...)
begin
return y, x
end
Note also that the begin keyword doesn't need to be on the same line as the function call as with the do-construct, since there should be no ambiguity in parsing this (the syntax ->... makes it clear that we need to complete the function definition). In principle, one could allow for any scoping block (for, while, let) to be used there, not just begin-end.

Going with this even further, multiple anonymous function arguments could be allowed with each ->... meaning sort of a deferred definition with the next N scoping blocks after the function call implementing the body of each anonymous function in turn, although this might be stretching it too far.

Anyway, I wonder what are your thoughts on this?



Reply | Threaded
Open this post in threaded view
|

Re: alternative do-block syntax proposal

Stefan Karpinski
So the problem with that syntax is that it's ambiguous how much of the expression _ appears in is part of the implied anonymous function. Scala uses the _ identifier like this and resolves that ambiguity with some imo crazy feedback from the type checker – iirc, when an _ appears like this (it has like a dozen different meanings in Scala), it the expression it turns into an anonymous function is the smallest one that is used in a context that expects a function value. As a result you need to run type inference and the type checker to parse Scala; this is why it's nuts to do this. Swift takes a much saner approach: it uses $1, $2, etc. for variables, and the extent of the anonymous function is explicitly delimited by curly braces.

We don't have the curly brace syntax available in Julia, so that's not an option. There's no way we're going to get types involved in parsing, so that's also not happening. What we need is a simple, purely syntactic rule for how much of the expression surrounding _ becomes an anonymous function. I've never come up with a satisfactory one.


On Tue, Jul 29, 2014 at 11:30 AM, Ethan Anderes <[hidden email]> wrote:

That is a cool suggestion. Would you also be able to do something like this

remotecall(2, _, args...) do x
 # blah
end

If so, it would accomplish what the where syntax was trying to do.

On Tuesday, July 29, 2014 7:45:44 AM UTC-7, Stefan Karpinski wrote:

To me the major driver for some variation on the current syntax is wanting to chain calls via the |> operator or something like it. I.e. something like this:

v |> f |> 1+_ |> sort(_, rev=true)

This is somewhat related to the idea of having an even terser anonymous function syntax.


On Tue, Jul 29, 2014 at 5:22 AM, Mike Innes <[hidden email]> wrote:
Since no one else has, I'll chime in in support of the current do block. If anything the proposal seems less intuitive/elegant to me.

The where block is nicer but a new keyword/syntax is going to need a pretty compelling reason to exist, and in this case you can simply write:

function f(x)
  # code...
end
map(f, 1:10)

Within a lexical scope (let block, function body, whatever) this will create an anonymous function rather than cluttering the global namespace. It also has the advantage that you can use multiple dispatch:

function test(xs)
  f(x::Int) = :int
  f(x::Real) = :real
  map(f, xs)
end

This is more flexible and IMO clearer, so long story short I think a major change in this area will be unlikely.


On 29 July 2014 09:42, Tomas Lycken <[hidden email]> wrote:

I like the alternative syntax! +1 =)

You can just as easily define f separately and pass it to the function; no ‘where’ clause needed.

Yes, of course. That is still an option for map, open et al, but the new syntax still has the advantage of making it very clear exactly where the function is going to be used. I find that when I use anonymous functions in various contexts, it’s usually because I know I won’t be re-using the function anywhere else, and therefore I don’t want to define anything that clutters up the name space. The proposed syntax (both the `(x,y)->...` variant and the `where` clause) still solve that problem, just as well as the current syntax with do blocks.

// T

On Monday, July 28, 2014 1:21:41 AM UTC+2, Alireza Nejati wrote:

That syntax loses anonymity.

You can just as easily define f separately and pass it to the function; no 'where' clause needed.

On Saturday, July 26, 2014 12:13:31 AM UTC+12, Tomek Trzeciak wrote:
When I first read about the do syntax in Julia I thought it's a neat sugar, but then it seemed a bit too magic to me. What I mean by magic is that

map([A, B, C]) do x
   
if x < 0 && iseven(x)
       
return 0
   
elseif x == 0
       
return 1
   
else
       
return x
   
end
end
this doesn't give any clue to the unversed that the do-block will create an anonymous function and pass it as the first argument to the function call preceding the block. As an alternative consider this:

map((x)->..., [A, B, C]) 
begin
    if x < 0 && iseven(x)
        return 0
    elseif x == 0
        return 1
    else
        return x
    end
end
I think this makes it much easier to guess the meaning of the construct, plus it has the benefit that in this way one could also allow to pass the anonymous as any other argument if desired, not just the first one:

somefunc(A, B, (x,y)->...)
begin
return y, x
end
Note also that the begin keyword doesn't need to be on the same line as the function call as with the do-construct, since there should be no ambiguity in parsing this (the syntax ->... makes it clear that we need to complete the function definition). In principle, one could allow for any scoping block (for, while, let) to be used there, not just begin-end.

Going with this even further, multiple anonymous function arguments could be allowed with each ->... meaning sort of a deferred definition with the next N scoping blocks after the function call implementing the body of each anonymous function in turn, although this might be stretching it too far.

Anyway, I wonder what are your thoughts on this?




Reply | Threaded
Open this post in threaded view
|

Re: alternative do-block syntax proposal

Tomek Trzeciak
In reply to this post by Mike Innes


On Tuesday, July 29, 2014 10:23:29 AM UTC+1, Mike Innes wrote:
Since no one else has, I'll chime in in support of the current do block. If anything the proposal seems less intuitive/elegant to me.

The where block is nicer but a new keyword/syntax is going to need a pretty compelling reason to exist, and in this case you can simply write:

function f(x)
  # code...
end
map(f, 1:10)

Within a lexical scope (let block, function body, whatever) this will create an anonymous function rather than cluttering the global namespace. It also has the advantage that you can use multiple dispatch:

function test(xs)
  f(x::Int) = :int
  f(x::Real) = :real
  map(f, xs)
end

This is more flexible and IMO clearer, so long story short I think a major change in this area will be unlikely.

I agree wit you that some this:

let
 
local f
 
function f(x::Int)
   
return x*x
 
end
  map
(f, [1 2 3])
end

is indeed quite clear, flexible and avoids cluttering the current scope (although somewhat more verbose, but still not too bad I'd say). Hmm, this makes me think that do could be done away with in the language entirely ;)
Reply | Threaded
Open this post in threaded view
|

Re: alternative do-block syntax proposal

Tomek Trzeciak
In reply to this post by Stefan Karpinski


On Tuesday, July 29, 2014 3:45:44 PM UTC+1, Stefan Karpinski wrote:
To me the major driver for some variation on the current syntax is wanting to chain calls via the |> operator or something like it. I.e. something like this:

v |> f |> 1+_ |> sort(_, rev=true)

This is somewhat related to the idea of having an even terser anonymous function syntax.

How about:

v |> f(...) |> 1+... |> sort(..., rev=true)

perhaps with the implied trialing (...) if not given explicitly, so one could write f instead of f(...)? What give me pause, though, is that this seems too much like a line noise (obfuscation contest in Julia, anyone? ;).
Reply | Threaded
Open this post in threaded view
|

Re: alternative do-block syntax proposal

Stefan Karpinski
Changing _ to ... doesn't really solve the problem (actually, it's more problematic since ... already has two (closely related) meanings.


On Tue, Jul 29, 2014 at 1:49 PM, Tomek Trzeciak <[hidden email]> wrote:


On Tuesday, July 29, 2014 3:45:44 PM UTC+1, Stefan Karpinski wrote:
To me the major driver for some variation on the current syntax is wanting to chain calls via the |> operator or something like it. I.e. something like this:

v |> f |> 1+_ |> sort(_, rev=true)

This is somewhat related to the idea of having an even terser anonymous function syntax.

How about:

v |> f(...) |> 1+... |> sort(..., rev=true)

perhaps with the implied trialing (...) if not given explicitly, so one could write f instead of f(...)? What give me pause, though, is that this seems too much like a line noise (obfuscation contest in Julia, anyone? ;).

Reply | Threaded
Open this post in threaded view
|

Re: alternative do-block syntax proposal

Mike Innes
In reply to this post by Stefan Karpinski
What do you think of the @as macro in Lazy.jl? It lets you write expressions like

@as _ v f (1+_) sort(_, rev=true)

For my money this kind of syntax is definitely useful, but not so common that it needs to be built into the parser – a macro seems like a good fit.

On Tuesday, 29 July 2014 15:45:44 UTC+1, Stefan Karpinski wrote:
To me the major driver for some variation on the current syntax is wanting to chain calls via the |> operator or something like it. I.e. something like this:

v |> f |> 1+_ |> sort(_, rev=true)

This is somewhat related to the idea of having an even terser anonymous function syntax.


On Tue, Jul 29, 2014 at 5:22 AM, Mike Innes <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="gvpMZ4bCvyIJ" onmousedown="this.href='javascript:';return true;" onclick="this.href='javascript:';return true;">mike.j...@...> wrote:
Since no one else has, I'll chime in in support of the current do block. If anything the proposal seems less intuitive/elegant to me.

The where block is nicer but a new keyword/syntax is going to need a pretty compelling reason to exist, and in this case you can simply write:

function f(x)
  # code...
end
map(f, 1:10)

Within a lexical scope (let block, function body, whatever) this will create an anonymous function rather than cluttering the global namespace. It also has the advantage that you can use multiple dispatch:

function test(xs)
  f(x::Int) = :int
  f(x::Real) = :real
  map(f, xs)
end

This is more flexible and IMO clearer, so long story short I think a major change in this area will be unlikely.


On 29 July 2014 09:42, Tomas Lycken <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="gvpMZ4bCvyIJ" onmousedown="this.href='javascript:';return true;" onclick="this.href='javascript:';return true;">tomas....@...> wrote:

I like the alternative syntax! +1 =)

You can just as easily define f separately and pass it to the function; no ‘where’ clause needed.

Yes, of course. That is still an option for map, open et al, but the new syntax still has the advantage of making it very clear exactly where the function is going to be used. I find that when I use anonymous functions in various contexts, it’s usually because I know I won’t be re-using the function anywhere else, and therefore I don’t want to define anything that clutters up the name space. The proposed syntax (both the `(x,y)->...` variant and the `where` clause) still solve that problem, just as well as the current syntax with do blocks.

// T

On Monday, July 28, 2014 1:21:41 AM UTC+2, Alireza Nejati wrote:

That syntax loses anonymity.

You can just as easily define f separately and pass it to the function; no 'where' clause needed.

On Saturday, July 26, 2014 12:13:31 AM UTC+12, Tomek Trzeciak wrote:
When I first read about the do syntax in Julia I thought it's a neat sugar, but then it seemed a bit too magic to me. What I mean by magic is that
map([A, B, C]) do x
   
if x < 0 && iseven(x)
       
return 0
   
elseif x == 0
       
return 1
   
else
       
return x
   
end
end
this doesn't give any clue to the unversed that the do-block will create an anonymous function and pass it as the first argument to the function call preceding the block. As an alternative consider this:
map((x)->..., [A, B, C]) 
begin
    if x < 0 && iseven(x)
        return 0
    elseif x == 0
        return 1
    else
        return x
    end
end
I think this makes it much easier to guess the meaning of the construct, plus it has the benefit that in this way one could also allow to pass the anonymous as any other argument if desired, not just the first one:
somefunc(A, B, (x,y)->...)
begin
return y, x
end
Note also that the begin keyword doesn't need to be on the same line as the function call as with the do-construct, since there should be no ambiguity in parsing this (the syntax ->... makes it clear that we need to complete the function definition). In principle, one could allow for any scoping block (for, while, let) to be used there, not just begin-end.

Going with this even further, multiple anonymous function arguments could be allowed with each ->... meaning sort of a deferred definition with the next N scoping blocks after the function call implementing the body of each anonymous function in turn, although this might be stretching it too far.

Anyway, I wonder what are your thoughts on this?



Reply | Threaded
Open this post in threaded view
|

Re: alternative do-block syntax proposal

Kevin Squire
I like the functionality (and was part of the earlier discussion), but find it hard to read without the `|>` separator (which is obviously extraneous, but a useful visual cue).

Kevin


On Tue, Jul 29, 2014 at 11:52 AM, Mike Innes <[hidden email]> wrote:
What do you think of the @as macro in Lazy.jl? It lets you write expressions like

@as _ v f (1+_) sort(_, rev=true)

For my money this kind of syntax is definitely useful, but not so common that it needs to be built into the parser – a macro seems like a good fit.


On Tuesday, 29 July 2014 15:45:44 UTC+1, Stefan Karpinski wrote:
To me the major driver for some variation on the current syntax is wanting to chain calls via the |> operator or something like it. I.e. something like this:

v |> f |> 1+_ |> sort(_, rev=true)

This is somewhat related to the idea of having an even terser anonymous function syntax.


On Tue, Jul 29, 2014 at 5:22 AM, Mike Innes <[hidden email]> wrote:
Since no one else has, I'll chime in in support of the current do block. If anything the proposal seems less intuitive/elegant to me.

The where block is nicer but a new keyword/syntax is going to need a pretty compelling reason to exist, and in this case you can simply write:

function f(x)
  # code...
end
map(f, 1:10)

Within a lexical scope (let block, function body, whatever) this will create an anonymous function rather than cluttering the global namespace. It also has the advantage that you can use multiple dispatch:

function test(xs)
  f(x::Int) = :int
  f(x::Real) = :real
  map(f, xs)
end

This is more flexible and IMO clearer, so long story short I think a major change in this area will be unlikely.


On 29 July 2014 09:42, Tomas Lycken <[hidden email]> wrote:

I like the alternative syntax! +1 =)

You can just as easily define f separately and pass it to the function; no ‘where’ clause needed.

Yes, of course. That is still an option for map, open et al, but the new syntax still has the advantage of making it very clear exactly where the function is going to be used. I find that when I use anonymous functions in various contexts, it’s usually because I know I won’t be re-using the function anywhere else, and therefore I don’t want to define anything that clutters up the name space. The proposed syntax (both the `(x,y)->...` variant and the `where` clause) still solve that problem, just as well as the current syntax with do blocks.

// T

On Monday, July 28, 2014 1:21:41 AM UTC+2, Alireza Nejati wrote:

That syntax loses anonymity.

You can just as easily define f separately and pass it to the function; no 'where' clause needed.

On Saturday, July 26, 2014 12:13:31 AM UTC+12, Tomek Trzeciak wrote:
When I first read about the do syntax in Julia I thought it's a neat sugar, but then it seemed a bit too magic to me. What I mean by magic is that

map([A, B, C]) do x
   
if x < 0 && iseven(x)
       
return 0
   
elseif x == 0
       
return 1
   
else
       
return x
   
end
end
this doesn't give any clue to the unversed that the do-block will create an anonymous function and pass it as the first argument to the function call preceding the block. As an alternative consider this:

map((x)->..., [A, B, C]) 
begin
    if x < 0 && iseven(x)
        return 0
    elseif x == 0
        return 1
    else
        return x
    end
end
I think this makes it much easier to guess the meaning of the construct, plus it has the benefit that in this way one could also allow to pass the anonymous as any other argument if desired, not just the first one:

somefunc(A, B, (x,y)->...)
begin
return y, x
end
Note also that the begin keyword doesn't need to be on the same line as the function call as with the do-construct, since there should be no ambiguity in parsing this (the syntax ->... makes it clear that we need to complete the function definition). In principle, one could allow for any scoping block (for, while, let) to be used there, not just begin-end.

Going with this even further, multiple anonymous function arguments could be allowed with each ->... meaning sort of a deferred definition with the next N scoping blocks after the function call implementing the body of each anonymous function in turn, although this might be stretching it too far.

Anyway, I wonder what are your thoughts on this?




Reply | Threaded
Open this post in threaded view
|

Re: alternative do-block syntax proposal

Stefan Karpinski
I agree with Kevin. I also think that if it was better supported, it might become useful enough to warrant better support ;-)


On Tue, Jul 29, 2014 at 3:03 PM, Kevin Squire <[hidden email]> wrote:
I like the functionality (and was part of the earlier discussion), but find it hard to read without the `|>` separator (which is obviously extraneous, but a useful visual cue).

Kevin


On Tue, Jul 29, 2014 at 11:52 AM, Mike Innes <[hidden email]> wrote:
What do you think of the @as macro in Lazy.jl? It lets you write expressions like

@as _ v f (1+_) sort(_, rev=true)

For my money this kind of syntax is definitely useful, but not so common that it needs to be built into the parser – a macro seems like a good fit.


On Tuesday, 29 July 2014 15:45:44 UTC+1, Stefan Karpinski wrote:
To me the major driver for some variation on the current syntax is wanting to chain calls via the |> operator or something like it. I.e. something like this:

v |> f |> 1+_ |> sort(_, rev=true)

This is somewhat related to the idea of having an even terser anonymous function syntax.


On Tue, Jul 29, 2014 at 5:22 AM, Mike Innes <[hidden email]> wrote:
Since no one else has, I'll chime in in support of the current do block. If anything the proposal seems less intuitive/elegant to me.

The where block is nicer but a new keyword/syntax is going to need a pretty compelling reason to exist, and in this case you can simply write:

function f(x)
  # code...
end
map(f, 1:10)

Within a lexical scope (let block, function body, whatever) this will create an anonymous function rather than cluttering the global namespace. It also has the advantage that you can use multiple dispatch:

function test(xs)
  f(x::Int) = :int
  f(x::Real) = :real
  map(f, xs)
end

This is more flexible and IMO clearer, so long story short I think a major change in this area will be unlikely.


On 29 July 2014 09:42, Tomas Lycken <[hidden email]> wrote:

I like the alternative syntax! +1 =)

You can just as easily define f separately and pass it to the function; no ‘where’ clause needed.

Yes, of course. That is still an option for map, open et al, but the new syntax still has the advantage of making it very clear exactly where the function is going to be used. I find that when I use anonymous functions in various contexts, it’s usually because I know I won’t be re-using the function anywhere else, and therefore I don’t want to define anything that clutters up the name space. The proposed syntax (both the `(x,y)->...` variant and the `where` clause) still solve that problem, just as well as the current syntax with do blocks.

// T

On Monday, July 28, 2014 1:21:41 AM UTC+2, Alireza Nejati wrote:

That syntax loses anonymity.

You can just as easily define f separately and pass it to the function; no 'where' clause needed.

On Saturday, July 26, 2014 12:13:31 AM UTC+12, Tomek Trzeciak wrote:
When I first read about the do syntax in Julia I thought it's a neat sugar, but then it seemed a bit too magic to me. What I mean by magic is that


map([A, B, C]) do x
   
if x < 0 && iseven(x)
       
return 0
   
elseif x == 0
       
return 1
   
else
       
return x
   
end
end
this doesn't give any clue to the unversed that the do-block will create an anonymous function and pass it as the first argument to the function call preceding the block. As an alternative consider this:


map((x)->..., [A, B, C]) 
begin
    if x < 0 && iseven(x)
        return 0
    elseif x == 0
        return 1
    else
        return x
    end
end
I think this makes it much easier to guess the meaning of the construct, plus it has the benefit that in this way one could also allow to pass the anonymous as any other argument if desired, not just the first one:


somefunc(A, B, (x,y)->...)
begin
return y, x
end
Note also that the begin keyword doesn't need to be on the same line as the function call as with the do-construct, since there should be no ambiguity in parsing this (the syntax ->... makes it clear that we need to complete the function definition). In principle, one could allow for any scoping block (for, while, let) to be used there, not just begin-end.

Going with this even further, multiple anonymous function arguments could be allowed with each ->... meaning sort of a deferred definition with the next N scoping blocks after the function call implementing the body of each anonymous function in turn, although this might be stretching it too far.

Anyway, I wonder what are your thoughts on this?





Reply | Threaded
Open this post in threaded view
|

Re: alternative do-block syntax proposal

Jeff Bezanson
I would be in favor of making |> built-in syntax for something like
@as, and handling the few existing method definitions for |> by
replacing them with functions that return closures.

On Tue, Jul 29, 2014 at 3:12 PM, Stefan Karpinski <[hidden email]> wrote:

> I agree with Kevin. I also think that if it was better supported, it might
> become useful enough to warrant better support ;-)
>
>
> On Tue, Jul 29, 2014 at 3:03 PM, Kevin Squire <[hidden email]>
> wrote:
>>
>> I like the functionality (and was part of the earlier discussion), but
>> find it hard to read without the `|>` separator (which is obviously
>> extraneous, but a useful visual cue).
>>
>> Kevin
>>
>>
>> On Tue, Jul 29, 2014 at 11:52 AM, Mike Innes <[hidden email]>
>> wrote:
>>>
>>> What do you think of the @as macro in Lazy.jl? It lets you write
>>> expressions like
>>>
>>> @as _ v f (1+_) sort(_, rev=true)
>>>
>>> For my money this kind of syntax is definitely useful, but not so common
>>> that it needs to be built into the parser – a macro seems like a good fit.
>>>
>>>
>>> On Tuesday, 29 July 2014 15:45:44 UTC+1, Stefan Karpinski wrote:
>>>>
>>>> To me the major driver for some variation on the current syntax is
>>>> wanting to chain calls via the |> operator or something like it. I.e.
>>>> something like this:
>>>>
>>>> v |> f |> 1+_ |> sort(_, rev=true)
>>>>
>>>>
>>>> This is somewhat related to the idea of having an even terser anonymous
>>>> function syntax.
>>>>
>>>>
>>>> On Tue, Jul 29, 2014 at 5:22 AM, Mike Innes <[hidden email]> wrote:
>>>>>
>>>>> Since no one else has, I'll chime in in support of the current do
>>>>> block. If anything the proposal seems less intuitive/elegant to me.
>>>>>
>>>>> The where block is nicer but a new keyword/syntax is going to need a
>>>>> pretty compelling reason to exist, and in this case you can simply write:
>>>>>
>>>>> function f(x)
>>>>>   # code...
>>>>> end
>>>>> map(f, 1:10)
>>>>>
>>>>> Within a lexical scope (let block, function body, whatever) this will
>>>>> create an anonymous function rather than cluttering the global namespace. It
>>>>> also has the advantage that you can use multiple dispatch:
>>>>>
>>>>> function test(xs)
>>>>>   f(x::Int) = :int
>>>>>   f(x::Real) = :real
>>>>>   map(f, xs)
>>>>> end
>>>>>
>>>>> This is more flexible and IMO clearer, so long story short I think a
>>>>> major change in this area will be unlikely.
>>>>>
>>>>>
>>>>> On 29 July 2014 09:42, Tomas Lycken <[hidden email]> wrote:
>>>>>>
>>>>>> I like the alternative syntax! +1 =)
>>>>>>
>>>>>> You can just as easily define f separately and pass it to the
>>>>>> function; no ‘where’ clause needed.
>>>>>>
>>>>>> Yes, of course. That is still an option for map, open et al, but the
>>>>>> new syntax still has the advantage of making it very clear exactly where the
>>>>>> function is going to be used. I find that when I use anonymous functions in
>>>>>> various contexts, it’s usually because I know I won’t be re-using the
>>>>>> function anywhere else, and therefore I don’t want to define anything that
>>>>>> clutters up the name space. The proposed syntax (both the `(x,y)->...`
>>>>>> variant and the `where` clause) still solve that problem, just as well as
>>>>>> the current syntax with do blocks.
>>>>>>
>>>>>> // T
>>>>>>
>>>>>> On Monday, July 28, 2014 1:21:41 AM UTC+2, Alireza Nejati wrote:
>>>>>>>
>>>>>>> That syntax loses anonymity.
>>>>>>>
>>>>>>> You can just as easily define f separately and pass it to the
>>>>>>> function; no 'where' clause needed.
>>>>>>>
>>>>>>> On Saturday, July 26, 2014 12:13:31 AM UTC+12, Tomek Trzeciak wrote:
>>>>>>>>
>>>>>>>> When I first read about the do syntax in Julia I thought it's a neat
>>>>>>>> sugar, but then it seemed a bit too magic to me. What I mean by magic is
>>>>>>>> that
>>>>>>>>
>>>>>>>> map([A, B, C]) do x
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>     if x < 0 && iseven(x)
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>         return 0
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>     elseif x == 0
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>         return 1
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>     else
>>>>>>>>         return x
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>     end
>>>>>>>> end
>>>>>>>>
>>>>>>>> this doesn't give any clue to the unversed that the do-block will
>>>>>>>> create an anonymous function and pass it as the first argument to the
>>>>>>>> function call preceding the block. As an alternative consider this:
>>>>>>>>
>>>>>>>> map((x)->..., [A, B, C])
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> begin
>>>>>>>>     if x < 0 && iseven(x)
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>         return 0
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>     elseif x == 0
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>         return 1
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>     else
>>>>>>>>         return x
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>     end
>>>>>>>> end
>>>>>>>>
>>>>>>>> I think this makes it much easier to guess the meaning of the
>>>>>>>> construct, plus it has the benefit that in this way one could also allow to
>>>>>>>> pass the anonymous as any other argument if desired, not just the first one:
>>>>>>>>
>>>>>>>> somefunc(A, B, (x,y)->...)
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> begin
>>>>>>>>     return y, x
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> end
>>>>>>>>
>>>>>>>> Note also that the begin keyword doesn't need to be on the same line
>>>>>>>> as the function call as with the do-construct, since there should be no
>>>>>>>> ambiguity in parsing this (the syntax ->... makes it clear that we need to
>>>>>>>> complete the function definition). In principle, one could allow for any
>>>>>>>> scoping block (for, while, let) to be used there, not just begin-end.
>>>>>>>>
>>>>>>>> Going with this even further, multiple anonymous function arguments
>>>>>>>> could be allowed with each ->... meaning sort of a deferred definition with
>>>>>>>> the next N scoping blocks after the function call implementing the body of
>>>>>>>> each anonymous function in turn, although this might be stretching it too
>>>>>>>> far.
>>>>>>>>
>>>>>>>> Anyway, I wonder what are your thoughts on this?
>>>>>
>>>>>
>>>>
>>
>
Reply | Threaded
Open this post in threaded view
|

Re: alternative do-block syntax proposal

James Porter
bumping my old PR for @as from an earlier round of this discussion :) https://github.com/JuliaLang/julia/pull/5734

I would be in favor of making |> do something like this automagically though.

On Tuesday, July 29, 2014 2:32:47 PM UTC-7, Jeff Bezanson wrote:
I would be in favor of making |> built-in syntax for something like
@as, and handling the few existing method definitions for |> by
replacing them with functions that return closures.

On Tue, Jul 29, 2014 at 3:12 PM, Stefan Karpinski <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="3mPhDhNvg3wJ" onmousedown="this.href='javascript:';return true;" onclick="this.href='javascript:';return true;">ste...@...> wrote:

> I agree with Kevin. I also think that if it was better supported, it might
> become useful enough to warrant better support ;-)
>
>
> On Tue, Jul 29, 2014 at 3:03 PM, Kevin Squire <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="3mPhDhNvg3wJ" onmousedown="this.href='javascript:';return true;" onclick="this.href='javascript:';return true;">kevin....@...>
> wrote:
>>
>> I like the functionality (and was part of the earlier discussion), but
>> find it hard to read without the `|>` separator (which is obviously
>> extraneous, but a useful visual cue).
>>
>> Kevin
>>
>>
>> On Tue, Jul 29, 2014 at 11:52 AM, Mike Innes <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="3mPhDhNvg3wJ" onmousedown="this.href='javascript:';return true;" onclick="this.href='javascript:';return true;">mike.j...@...>
>> wrote:
>>>
>>> What do you think of the @as macro in Lazy.jl? It lets you write
>>> expressions like
>>>
>>> @as _ v f (1+_) sort(_, rev=true)
>>>
>>> For my money this kind of syntax is definitely useful, but not so common
>>> that it needs to be built into the parser – a macro seems like a good fit.
>>>
>>>
>>> On Tuesday, 29 July 2014 15:45:44 UTC+1, Stefan Karpinski wrote:
>>>>
>>>> To me the major driver for some variation on the current syntax is
>>>> wanting to chain calls via the |> operator or something like it. I.e.
>>>> something like this:
>>>>
>>>> v |> f |> 1+_ |> sort(_, rev=true)
>>>>
>>>>
>>>> This is somewhat related to the idea of having an even terser anonymous
>>>> function syntax.
>>>>
>>>>
>>>> On Tue, Jul 29, 2014 at 5:22 AM, Mike Innes <[hidden email]> wrote:
>>>>>
>>>>> Since no one else has, I'll chime in in support of the current do
>>>>> block. If anything the proposal seems less intuitive/elegant to me.
>>>>>
>>>>> The where block is nicer but a new keyword/syntax is going to need a
>>>>> pretty compelling reason to exist, and in this case you can simply write:
>>>>>
>>>>> function f(x)
>>>>>   # code...
>>>>> end
>>>>> map(f, 1:10)
>>>>>
>>>>> Within a lexical scope (let block, function body, whatever) this will
>>>>> create an anonymous function rather than cluttering the global namespace. It
>>>>> also has the advantage that you can use multiple dispatch:
>>>>>
>>>>> function test(xs)
>>>>>   f(x::Int) = :int
>>>>>   f(x::Real) = :real
>>>>>   map(f, xs)
>>>>> end
>>>>>
>>>>> This is more flexible and IMO clearer, so long story short I think a
>>>>> major change in this area will be unlikely.
>>>>>
>>>>>
>>>>> On 29 July 2014 09:42, Tomas Lycken <[hidden email]> wrote:
>>>>>>
>>>>>> I like the alternative syntax! +1 =)
>>>>>>
>>>>>> You can just as easily define f separately and pass it to the
>>>>>> function; no ‘where’ clause needed.
>>>>>>
>>>>>> Yes, of course. That is still an option for map, open et al, but the
>>>>>> new syntax still has the advantage of making it very clear exactly where the
>>>>>> function is going to be used. I find that when I use anonymous functions in
>>>>>> various contexts, it’s usually because I know I won’t be re-using the
>>>>>> function anywhere else, and therefore I don’t want to define anything that
>>>>>> clutters up the name space. The proposed syntax (both the `(x,y)->...`
>>>>>> variant and the `where` clause) still solve that problem, just as well as
>>>>>> the current syntax with do blocks.
>>>>>>
>>>>>> // T
>>>>>>
>>>>>> On Monday, July 28, 2014 1:21:41 AM UTC+2, Alireza Nejati wrote:
>>>>>>>
>>>>>>> That syntax loses anonymity.
>>>>>>>
>>>>>>> You can just as easily define f separately and pass it to the
>>>>>>> function; no 'where' clause needed.
>>>>>>>
>>>>>>> On Saturday, July 26, 2014 12:13:31 AM UTC+12, Tomek Trzeciak wrote:
>>>>>>>>
>>>>>>>> When I first read about the do syntax in Julia I thought it's a neat
>>>>>>>> sugar, but then it seemed a bit too magic to me. What I mean by magic is
>>>>>>>> that
>>>>>>>>
>>>>>>>> map([A, B, C]) do x
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>     if x < 0 && iseven(x)
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>         return 0
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>     elseif x == 0
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>         return 1
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>     else
>>>>>>>>         return x
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>     end
>>>>>>>> end
>>>>>>>>
>>>>>>>> this doesn't give any clue to the unversed that the do-block will
>>>>>>>> create an anonymous function and pass it as the first argument to the
>>>>>>>> function call preceding the block. As an alternative consider this:
>>>>>>>>
>>>>>>>> map((x)->..., [A, B, C])
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> begin
>>>>>>>>     if x < 0 && iseven(x)
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>         return 0
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>     elseif x == 0
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>         return 1
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>     else
>>>>>>>>         return x
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>     end
>>>>>>>> end
>>>>>>>>
>>>>>>>> I think this makes it much easier to guess the meaning of the
>>>>>>>> construct, plus it has the benefit that in this way one could also allow to
>>>>>>>> pass the anonymous as any other argument if desired, not just the first one:
>>>>>>>>
>>>>>>>> somefunc(A, B, (x,y)->...)
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> begin
>>>>>>>>     return y, x
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> end
>>>>>>>>
>>>>>>>> Note also that the begin keyword doesn't need to be on the same line
>>>>>>>> as the function call as with the do-construct, since there should be no
>>>>>>>> ambiguity in parsing this (the syntax ->... makes it clear that we need to
>>>>>>>> complete the function definition). In principle, one could allow for any
>>>>>>>> scoping block (for, while, let) to be used there, not just begin-end.
>>>>>>>>
>>>>>>>> Going with this even further, multiple anonymous function arguments
>>>>>>>> could be allowed with each ->... meaning sort of a deferred definition with
>>>>>>>> the next N scoping blocks after the function call implementing the body of
>>>>>>>> each anonymous function in turn, although this might be stretching it too
>>>>>>>> far.
>>>>>>>>
>>>>>>>> Anyway, I wonder what are your thoughts on this?
>>>>>
>>>>>
>>>>
>>
>