digitalmars.D - Curious thoughts, regarding functional programming
- Gor Gyolchanyan (35/35) Oct 12 2011 I find myself constantly dreaming about a syntax sugar, which would
- Nick Sabalausky (3/11) Oct 12 2011 That's actually a pretty common feature request for D.
- simendsjo (8/21) Oct 12 2011 I don't find this very ugly:
- Jacob Carlborg (35/70) Oct 12 2011 This has been proposed several times before. Something like, if a
- Gor Gyolchanyan (10/85) Oct 12 2011 The semicolon technique has occurred to me, but seemed a bit too
- Jacob Carlborg (4/98) Oct 12 2011 --
- Gor Gyolchanyan (8/111) Oct 12 2011 You never know when exactly and in which conditions will that delegate
- Jacob Carlborg (16/19) Oct 12 2011 If a function implements something similar to a loop I would like to be
- Simen Kjaeraas (7/24) Oct 12 2011 However, a lot of code using this syntax would be more complex than what
- Jacob Carlborg (5/30) Oct 12 2011 This answer to a stack overflow question explains how it works in Ruby:
- Nick Sabalausky (37/48) Oct 12 2011 Better (IMHO):
-
kennytm
(11/73)
Oct 12 2011
The 'break
' syntax conflicts with the 'break - Jacob Carlborg (13/66) Oct 12 2011 That's actually how it works in Ruby as well. Ruby also has both lambdas...
I find myself constantly dreaming about a syntax sugar, which would make me (and probably, many others) very happy. An important and popular aspect of functional programming is the ability to pass delegate literals to functions. The downside to this is the ugliness of the resulting code, which discourages doing so: std.concurrency.spawn({ foreach(i, 0.100) { } }); This piece of code has way too much punctuation. Worst of all, the entire delegate literal is crammed inside the function call parentheses. It looks especially ugly when the delegate literal is not a one-liner. The way I saw it in my dreams is: spawn() { foreach(i; 0..100) { } }; What happened here is, that the delegate moved outside the parentheses. This looks awfully like a function definition, right? Wrong! This does not have a return type, the parameters are not definitions, they are values and there is a semicolon at the end (which quickly gives a visual clue of what this thing actually is). Hey, wait a minute! What about parameters to delegates and what about other delegate parameters? Well, this will work with only one delegate (or function) parameter and the parameters could be specified in a second set of parentheses (again this would look like a template, but it actually won't): spawn(5, 4, 65)(int x, int y, int z) { /*...*/ }; IMO, this looks WAY more beautiful, then what we have now. I don't see any reason why this would break existing code. I know, I know this is hard to implement and we got better things to do. I'm just saying. This would look good.
Oct 12 2011
"Gor Gyolchanyan" <gor.f.gyolchanyan gmail.com> wrote in message news:mailman.62.1318407737.24802.digitalmars-d puremagic.com...spawn(5, 4, 65)(int x, int y, int z) { /*...*/ }; IMO, this looks WAY more beautiful, then what we have now. I don't see any reason why this would break existing code. I know, I know this is hard to implement and we got better things to do. I'm just saying. This would look good.That's actually a pretty common feature request for D.
Oct 12 2011
On 12.10.2011 11:57, Nick Sabalausky wrote:"Gor Gyolchanyan"<gor.f.gyolchanyan gmail.com> wrote in message news:mailman.62.1318407737.24802.digitalmars-d puremagic.com...I don't find this very ugly: spawn(5,4,65)( (int x, int y, int z) { /*...*/ }); I would much rather push uniformed function call syntax (correct definition?) forward.spawn(5, 4, 65)(int x, int y, int z) { /*...*/ }; IMO, this looks WAY more beautiful, then what we have now. I don't see any reason why this would break existing code. I know, I know this is hard to implement and we got better things to do. I'm just saying. This would look good.That's actually a pretty common feature request for D.
Oct 12 2011
On 2011-10-12 10:21, Gor Gyolchanyan wrote:I find myself constantly dreaming about a syntax sugar, which would make me (and probably, many others) very happy. An important and popular aspect of functional programming is the ability to pass delegate literals to functions. The downside to this is the ugliness of the resulting code, which discourages doing so: std.concurrency.spawn({ foreach(i, 0.100) { } }); This piece of code has way too much punctuation. Worst of all, the entire delegate literal is crammed inside the function call parentheses. It looks especially ugly when the delegate literal is not a one-liner. The way I saw it in my dreams is: spawn() { foreach(i; 0..100) { } }; What happened here is, that the delegate moved outside the parentheses. This looks awfully like a function definition, right? Wrong! This does not have a return type, the parameters are not definitions, they are values and there is a semicolon at the end (which quickly gives a visual clue of what this thing actually is). Hey, wait a minute! What about parameters to delegates and what about other delegate parameters? Well, this will work with only one delegate (or function) parameter and the parameters could be specified in a second set of parentheses (again this would look like a template, but it actually won't): spawn(5, 4, 65)(int x, int y, int z) { /*...*/ }; IMO, this looks WAY more beautiful, then what we have now. I don't see any reason why this would break existing code. I know, I know this is hard to implement and we got better things to do. I'm just saying. This would look good.This has been proposed several times before. Something like, if a function takes a delegate as its last parameter then this syntax would work: void unless (bool condition, void delegate () dg) { if (condition) dg(); } unless(a == b) { // delegate } And passing arguments to the delegate: foo(1 ; 2){} Any arguments to the left of the semicolon would be passed to the delegate. When this feature is talked about you usually want more things, like, what I would like to call, "soft" and "hard" returns. void iterate (int start, int end, void delegate (int a) dg) { foreach (a ; start .. end) dg(); } When this delegate is called you want to both be able to just return from the delegate but also return from "foo". iterate(1, 10 ; int a) { if (a == 2) yield; // soft return, just returns from the delegate else if (a == 4) return; // hard return, return from both the delegate and the function that called the delegate } Currently we only have "soft" returns from delegates. -- /Jacob Carlborg
Oct 12 2011
The semicolon technique has occurred to me, but seemed a bit too radical (I loved it nonetheless). The "hard" return should not be available IMO. The delegate should never have control over who calls it. It's totally wrong... IMO. On Wed, Oct 12, 2011 at 4:13 PM, Jacob Carlborg <doob me.com> wrote:On 2011-10-12 10:21, Gor Gyolchanyan wrote:nI find myself constantly dreaming about a syntax sugar, which would make me (and probably, many others) very happy. An important and popular aspect of functional programming is the ability to pass delegate literals to functions. The downside to this is the ugliness of the resulting code, which discourages doing so: std.concurrency.spawn({ foreach(i, 0.100) { =A0} }); This piece of code has way too much punctuation. Worst of all, the entire delegate literal is crammed inside the function call parentheses. It looks especially ugly when the delegate literal is not a one-liner. The way I saw it in my dreams is: spawn() { =A0 =A0 foreach(i; 0..100) { } }; What happened here is, that the delegate moved outside the parentheses. This looks awfully like a function definition, right? Wrong! This does not have a return type, the parameters are not definitions, they are values and there is a semicolon at the end (which quickly gives a visual clue of what this thing actually is). Hey, wait a minute! What about parameters to delegates and what about other delegate parameters? Well, this will work with only one delegate (or function) parameter and the parameters could be specified in a second set of parentheses (again this would look like a template, but it actually won't): spawn(5, 4, 65)(int x, int y, int z) { =A0 =A0/*...*/ }; IMO, this looks WAY more beautiful, then what we have now. I don't see any reason why this would break existing code. I know, I know this is hard to implement and we got better things to do. I'm just saying. This would look good.This has been proposed several times before. Something like, if a functio=takes a delegate as its last parameter then this syntax would work: void unless (bool condition, void delegate () dg) { =A0 =A0if (condition) =A0 =A0 =A0 =A0dg(); } unless(a =3D=3D b) { =A0 =A0// delegate } And passing arguments to the delegate: foo(1 ; 2){} Any arguments to the left of the semicolon would be passed to the delegat=e.When this feature is talked about you usually want more things, like, wha=t Iwould like to call, "soft" and "hard" returns. void iterate (int start, int end, void delegate (int a) dg) { =A0 =A0foreach (a ; start .. end) =A0 =A0 =A0 =A0dg(); } When this delegate is called you want to both be able to just return from the delegate but also return from "foo". iterate(1, 10 ; int a) { =A0 =A0if (a =3D=3D 2) =A0 =A0 =A0 =A0yield; // soft return, just returns from the delegate =A0 =A0else if (a =3D=3D 4) =A0 =A0 =A0 =A0return; // hard return, return from both the delegate and =thefunction that called the delegate } Currently we only have "soft" returns from delegates. -- /Jacob Carlborg
Oct 12 2011
On 2011-10-12 14:35, Gor Gyolchanyan wrote:The semicolon technique has occurred to me, but seemed a bit too radical (I loved it nonetheless). The "hard" return should not be available IMO. The delegate should never have control over who calls it. It's totally wrong... IMO.It has it uses and it's possible to do so in Ruby.On Wed, Oct 12, 2011 at 4:13 PM, Jacob Carlborg<doob me.com> wrote:-- /Jacob CarlborgOn 2011-10-12 10:21, Gor Gyolchanyan wrote:I find myself constantly dreaming about a syntax sugar, which would make me (and probably, many others) very happy. An important and popular aspect of functional programming is the ability to pass delegate literals to functions. The downside to this is the ugliness of the resulting code, which discourages doing so: std.concurrency.spawn({ foreach(i, 0.100) { } }); This piece of code has way too much punctuation. Worst of all, the entire delegate literal is crammed inside the function call parentheses. It looks especially ugly when the delegate literal is not a one-liner. The way I saw it in my dreams is: spawn() { foreach(i; 0..100) { } }; What happened here is, that the delegate moved outside the parentheses. This looks awfully like a function definition, right? Wrong! This does not have a return type, the parameters are not definitions, they are values and there is a semicolon at the end (which quickly gives a visual clue of what this thing actually is). Hey, wait a minute! What about parameters to delegates and what about other delegate parameters? Well, this will work with only one delegate (or function) parameter and the parameters could be specified in a second set of parentheses (again this would look like a template, but it actually won't): spawn(5, 4, 65)(int x, int y, int z) { /*...*/ }; IMO, this looks WAY more beautiful, then what we have now. I don't see any reason why this would break existing code. I know, I know this is hard to implement and we got better things to do. I'm just saying. This would look good.This has been proposed several times before. Something like, if a function takes a delegate as its last parameter then this syntax would work: void unless (bool condition, void delegate () dg) { if (condition) dg(); } unless(a == b) { // delegate } And passing arguments to the delegate: foo(1 ; 2){} Any arguments to the left of the semicolon would be passed to the delegate. When this feature is talked about you usually want more things, like, what I would like to call, "soft" and "hard" returns. void iterate (int start, int end, void delegate (int a) dg) { foreach (a ; start .. end) dg(); } When this delegate is called you want to both be able to just return from the delegate but also return from "foo". iterate(1, 10 ; int a) { if (a == 2) yield; // soft return, just returns from the delegate else if (a == 4) return; // hard return, return from both the delegate and the function that called the delegate } Currently we only have "soft" returns from delegates. -- /Jacob Carlborg
Oct 12 2011
You never know when exactly and in which conditions will that delegate get called. You can't decide to quit something you don't know anything about. On Wed, Oct 12, 2011 at 8:08 PM, Jacob Carlborg <doob me.com> wrote:On 2011-10-12 14:35, Gor Gyolchanyan wrote:.The semicolon technique has occurred to me, but seemed a bit too radical (I loved it nonetheless). The "hard" return should not be available IMO. The delegate should never have control over who calls it. It's totally wrong... IMO.It has it uses and it's possible to do so in Ruby.On Wed, Oct 12, 2011 at 4:13 PM, Jacob Carlborg<doob me.com> =A0wrote:On 2011-10-12 10:21, Gor Gyolchanyan wrote:I find myself constantly dreaming about a syntax sugar, which would make me (and probably, many others) very happy. An important and popular aspect of functional programming is the ability to pass delegate literals to functions. The downside to this is the ugliness of the resulting code, which discourages doing so: std.concurrency.spawn({ foreach(i, 0.100) { =A0} }); This piece of code has way too much punctuation. Worst of all, the entire delegate literal is crammed inside the function call parentheses. It looks especially ugly when the delegate literal is not a one-liner. The way I saw it in my dreams is: spawn() { =A0 =A0 foreach(i; 0..100) { } }; What happened here is, that the delegate moved outside the parentheses=o.This looks awfully like a function definition, right? Wrong! This does not have a return type, the parameters are not definitions, they are values and there is a semicolon at the end (which quickly gives a visual clue of what this thing actually is). Hey, wait a minute! What about parameters to delegates and what about other delegate parameters? Well, this will work with only one delegate (or function) parameter and the parameters could be specified in a second set of parentheses (again this would look like a template, but it actually won't): spawn(5, 4, 65)(int x, int y, int z) { =A0 =A0/*...*/ }; IMO, this looks WAY more beautiful, then what we have now. I don't see any reason why this would break existing code. I know, I know this is hard to implement and we got better things to d=omI'm just saying. This would look good.This has been proposed several times before. Something like, if a function takes a delegate as its last parameter then this syntax would work: void unless (bool condition, void delegate () dg) { =A0 =A0if (condition) =A0 =A0 =A0 =A0dg(); } unless(a =3D=3D b) { =A0 =A0// delegate } And passing arguments to the delegate: foo(1 ; 2){} Any arguments to the left of the semicolon would be passed to the delegate. When this feature is talked about you usually want more things, like, what I would like to call, "soft" and "hard" returns. void iterate (int start, int end, void delegate (int a) dg) { =A0 =A0foreach (a ; start .. end) =A0 =A0 =A0 =A0dg(); } When this delegate is called you want to both be able to just return fr=d thethe delegate but also return from "foo". iterate(1, 10 ; int a) { =A0 =A0if (a =3D=3D 2) =A0 =A0 =A0 =A0yield; // soft return, just returns from the delegate =A0 =A0else if (a =3D=3D 4) =A0 =A0 =A0 =A0return; // hard return, return from both the delegate an=-- /Jacob Carlborgfunction that called the delegate } Currently we only have "soft" returns from delegates. -- /Jacob Carlborg
Oct 12 2011
On 2011-10-12 18:18, Gor Gyolchanyan wrote:You never know when exactly and in which conditions will that delegate get called. You can't decide to quit something you don't know anything about.If a function implements something similar to a loop I would like to be able to abort it with a return just as you can with a loop built into the language. void loop (void delegate () dg) { while (true) dg(); } loop { if (someCondition) return; // stops the loop } -- /Jacob Carlborg
Oct 12 2011
On Wed, 12 Oct 2011 19:00:56 +0200, Jacob Carlborg <doob me.com> wrote:On 2011-10-12 18:18, Gor Gyolchanyan wrote:However, a lot of code using this syntax would be more complex than what you indicate. Should it work simply as a break in the loop? What if it is a recursive function? There is a reason why opApply is designed the way it is. -- SimenYou never know when exactly and in which conditions will that delegate get called. You can't decide to quit something you don't know anything about.If a function implements something similar to a loop I would like to be able to abort it with a return just as you can with a loop built into the language. void loop (void delegate () dg) { while (true) dg(); } loop { if (someCondition) return; // stops the loop }
Oct 12 2011
On 2011-10-12 19:40, Simen Kjaeraas wrote:On Wed, 12 Oct 2011 19:00:56 +0200, Jacob Carlborg <doob me.com> wrote:This answer to a stack overflow question explains how it works in Ruby: http://stackoverflow.com/questions/1402757/how-to-break-out-from-a-ruby-block#answer-1402764 -- /Jacob CarlborgOn 2011-10-12 18:18, Gor Gyolchanyan wrote:However, a lot of code using this syntax would be more complex than what you indicate. Should it work simply as a break in the loop? What if it is a recursive function? There is a reason why opApply is designed the way it is.You never know when exactly and in which conditions will that delegate get called. You can't decide to quit something you don't know anything about.If a function implements something similar to a loop I would like to be able to abort it with a return just as you can with a loop built into the language. void loop (void delegate () dg) { while (true) dg(); } loop { if (someCondition) return; // stops the loop }
Oct 12 2011
"Jacob Carlborg" <doob me.com> wrote in message news:j740a6$2t8m$1 digitalmars.com...When this delegate is called you want to both be able to just return from the delegate but also return from "foo". iterate(1, 10 ; int a) { if (a == 2) yield; // soft return, just returns from the delegate else if (a == 4) return; // hard return, return from both the delegate and the function that called the delegate } Currently we only have "soft" returns from delegates.Better (IMHO): void foo() { iterate(int a; 1, 10) { if (a == 2) continue; // return from just the delegate else if (a == 4) break; // return from both delegate and iterate else if (a == 6) return; // return from the delegate, iterate, and foo } } Ie, same syntax and semantics as foreach. Also, a couple new things that foreach doesn't have to deal with: auto x = map(i; 1, 10) { //continue; // Error: map's dg can't return void continue i*2; // OK } assert(x == [2, 4, 6, etc...]); // Conventiently ignoring ranges just for the sake of illustration Of course, maybe it would be better to require "yield" in such a case (and maybe make "yield" synonymous with "continue" for void delegates?), but there's a lot of resistance against new keywords. And, one last thing to take care of: auto x = iterate(i; 1, 10) { if(i == 4) { //break; // Error: need a return value break i*2; // OK } } assert(x == 8);
Oct 12 2011
"Nick Sabalausky" <a a.a> wrote:"Jacob Carlborg" <doob me.com> wrote in message news:j740a6$2t8m$1 digitalmars.com...The 'break <expr>' syntax conflicts with the 'break <label>' syntax, so -1 to this. i: auto x = iterate(i; 1, 10) { foreach (j; 0 .. i) break i; // what should it do? break i; } Perhaps you need to require parenthesis, like 'break (i);' and 'break (i*2);'.When this delegate is called you want to both be able to just return from the delegate but also return from "foo". iterate(1, 10 ; int a) { if (a == 2) yield; // soft return, just returns from the delegate else if (a == 4) return; // hard return, return from both the delegate and the function that called the delegate } Currently we only have "soft" returns from delegates.Better (IMHO): void foo() { iterate(int a; 1, 10) { if (a == 2) continue; // return from just the delegate else if (a == 4) break; // return from both delegate and iterate else if (a == 6) return; // return from the delegate, iterate, and foo } } Ie, same syntax and semantics as foreach. Also, a couple new things that foreach doesn't have to deal with: auto x = map(i; 1, 10) { //continue; // Error: map's dg can't return void continue i*2; // OK } assert(x == [2, 4, 6, etc...]); // Conventiently ignoring ranges just for the sake of illustration Of course, maybe it would be better to require "yield" in such a case (and maybe make "yield" synonymous with "continue" for void delegates?), but there's a lot of resistance against new keywords. And, one last thing to take care of: auto x = iterate(i; 1, 10) { if(i == 4) { //break; // Error: need a return value break i*2; // OK } } assert(x == 8);
Oct 12 2011
On 2011-10-12 22:56, Nick Sabalausky wrote:"Jacob Carlborg"<doob me.com> wrote in message news:j740a6$2t8m$1 digitalmars.com...That's actually how it works in Ruby as well. Ruby also has both lambdas and blocks, the only difference between them is that you can't return/break from a lambda but you can from a block (I hope I got this right). This answer to a stack overflow question explains how it works in Ruby: http://stackoverflow.com/questions/1402757/how-to-break-out-from-a-ruby- lock#answer-1402764When this delegate is called you want to both be able to just return from the delegate but also return from "foo". iterate(1, 10 ; int a) { if (a == 2) yield; // soft return, just returns from the delegate else if (a == 4) return; // hard return, return from both the delegate and the function that called the delegate } Currently we only have "soft" returns from delegates.Better (IMHO): void foo() { iterate(int a; 1, 10) { if (a == 2) continue; // return from just the delegate else if (a == 4) break; // return from both delegate and iterate else if (a == 6) return; // return from the delegate, iterate, and foo } }Ie, same syntax and semantics as foreach. Also, a couple new things that foreach doesn't have to deal with: auto x = map(i; 1, 10) { //continue; // Error: map's dg can't return void continue i*2; // OK } assert(x == [2, 4, 6, etc...]); // Conventiently ignoring ranges just for the sake of illustration Of course, maybe it would be better to require "yield" in such a case (and maybe make "yield" synonymous with "continue" for void delegates?), but there's a lot of resistance against new keywords.Yeah, I know that.And, one last thing to take care of: auto x = iterate(i; 1, 10) { if(i == 4) { //break; // Error: need a return value break i*2; // OK } } assert(x == 8);Yeah, assuming "iterate" takes a delegate that returns something. But that would be nice, to create, what look like, statements that return a values. -- /Jacob Carlborg
Oct 12 2011