Re: How can you read and understand the source of *naryFun in functional.d?
On 1/30/11, Philippe Sigaud wrote: > If anyone is interested, I coded a n-args version of > unaryFun/binaryFun called naryFun. If you use 'a', 'b', ... as args > names, it can automatically determine the templated function arity. Is this going in the next release? There's an nary template in std.functional right now but it's commented out. It does look like an older attempt that probably didn't work.
Re: How can you read and understand the source of *naryFun in functional.d?
On Sun, Jan 30, 2011 at 12:03, Tom wrote: > I would like to thank you for that such a great explanation of the > Template-based > programming in that unary example. I think it's great you have uploaded that > to > the wiki4d, and it's definite will help a lot of people that come from other > common languages background (like C, C# and Python) that don't support full > templating, to understand that design pattern. > And with that close tracking to the functional.d code, I thing but not sure > that > we've found some bugs. I will do some testing later today, and if I will see > what > I think to be wrong, I'll update. If anyone is interested, I coded a n-args version of unaryFun/binaryFun called naryFun. If you use 'a', 'b', ... as args names, it can automatically determine the templated function arity. So naryFun!"a + b * c - sin(d-a)" is a 4-args template function. It's there: http://svn.dsource.org/projects/dranges/trunk/dranges/docs/functional.html (look for naryFun at the bottom) code is here: http://dsource.org/projects/dranges/browser/trunk/dranges/functional.d It could be simpler now: when I did it 18 months ago, CTFE wasn't so powerful. The looping templates can now easily be done with a simple foreach. This has been on my todo list for quite some time... Philippe
Re: How can you read and understand the source of *naryFun in functional.d?
I would like to thank you for that such a great explanation of the Template-based programming in that unary example. I think it's great you have uploaded that to the wiki4d, and it's definite will help a lot of people that come from other common languages background (like C, C# and Python) that don't support full templating, to understand that design pattern. And with that close tracking to the functional.d code, I thing but not sure that we've found some bugs. I will do some testing later today, and if I will see what I think to be wrong, I'll update. and again, Thanks
Re: How can you read and understand the source of *naryFun in functional.d?
On Saturday 29 January 2011 16:01:06 Andrej Mitrovic wrote: > Well now I'm feeling really stupid because apparently this is how it > *should* work, at least according to the docs. > > I'd love to see 'alias symbol this' work even with multiple > declarations. It'd be nicee.. It's how it should work according to TDPL. It'll get fixed It's just a question of when. - Jonathan M Davis
Re: How can you read and understand the source of *naryFun in functional.d?
Well now I'm feeling really stupid because apparently this is how it *should* work, at least according to the docs. I'd love to see 'alias symbol this' work even with multiple declarations. It'd be nicee..
Re: How can you read and understand the source of *naryFun in functional.d?
Well I've updated the tutorial anyway. I just left a note and used an templateImpl companion template.
Re: How can you read and understand the source of *naryFun in functional.d?
Oh yeah, it's that damn bug where you can't have multiple declarations, otherwise aliases don't work. I still don't know if that bug will ever be fixed or if I should add that to the tutorial.
Re: How can you read and understand the source of *naryFun in functional.d?
Wait, why won't this compile?: template foo(int value) { int result; alias result foo; } void main() { writeln( foo!(4) ); }
Re: How can you read and understand the source of *naryFun in functional.d?
Done: http://prowiki.org/wiki4d/wiki.cgi?D__Tutorial/D2Templates I've replaced my obvious English mistakes with slightly less obvious ones. Kinda wish prowiki had a nicer code display though (syntax highlighting would be nice).
Re: How can you read and understand the source of *naryFun in functional.d?
Save this somewhere or it will be lost here ;)
Re: How can you read and understand the source of *naryFun in functional.d?
Fix: So essentially it allows us to use any string of characters instead of "b". I've meant "a" here, not "b".
Re: How can you read and understand the source of *naryFun in functional.d?
Note when I said "But, we *did* pass a valid argument," I was refering to the original code example I gave at the top where we called unaryFun for the first time.
Re: How can you read and understand the source of *naryFun in functional.d?
Woops, sorry about the missing function definition after the line: "unaryFun takes the string argument and might create this function:" This should be maybe: int unaryFun(int a) { return (a & 1) == 0; } But that's oversimplification since that instantiation is a function template itself, not a specific function.
Re: How can you read and understand the source of *naryFun in functional.d?
I hope this gets pasted right, otherwise I'll have to open a freakin' blog. :) Up until a few months ago, I had no experience with templates whatsoever. At first, I started using function templates, because they were the easiest to grasp. Or so I thought. Basically I just used function templates as if they are a special kind of function that takes any types of arguments. Sort of like having a regular Python function in your D code. I didn't quite grasp the point of templates back then. What really opened my eyes was the realization that in D there's a distinct notion between manipulating types at compile-time and manipulating types at run-time. Once I've realized that, I knew why template arguments have to be known at compile time, because templates are a compile-time feature. And templates aren't really a "type" at runtime, they're only visible at compile-time. They're just "placeholders" with their own scope, and they hold declarations in that scope. And to access those declarations (or fields would be a proper word), you generally use the dot operator. There's also the eponymous trick where you can use the template instantiation itself to refer to one of its fields (this is useful when you're only interesting in getting back one result, as it saves you the burden of having to explicitly specify that field when instantiating the template). Then, I've realized that templates can be used almost anywhere. A template can have fields which are templated structs and classes, which in turn can have templated functions, which in turn have templated declarations in them, and the functions can have templated return values. So, let's talk about unaryFun now. unaryFun is a template which has the ability to construct a function, by simply passing a string as an argument. It's named *unary* because it constructs a function that takes only a single argument. You pass the string in the syntax form where it's as if you're only writing the return expression. unaryFun has the ability to convert some special predefined characters to parameters of a function. For example, it recognizes that 'a' should be replaced with the argument to the newly constructed function. Here's a simple instantiation of unaryFun: unaryFun!("(a & 1) == 0") unaryFun takes the string argument and might create this function: Let me walk you through unaryFun line by line (I'm using DMD 2.051). First, our example code: alias unaryFun!("(a & 1) == 0") isEven; assert(isEven(2) && !isEven(1)); Now open std.functional. Line 40: unaryFun instantiates unaryFunImpl. You'll notice it passes the same arguments to unaryFunImpl as the ones it got from the calling code. We passed a string, and the two other arguments are set to 'false' and 'a' by default, since we didn't specify them. Once the unaryFunImpl template is instantiated, we can select any of its fields with the dot operator. In this case, we're interested in the result field. So.. what does the alias do? It's a nice thing called the eponymous trick, where you can use the name of the template itself as the result of the instantiation. In other words, if you alias the name of a template to some declaration, when you instantiate that template you won't have to use the dot prefix to get a single result. A quick example without the eponymous trick: template foo(int value) { int result = value; } void main() { writeln( foo!(4).result ); } And here's one with the eponymous trick: template foo(int value) { int result = value; alias result foo; // we've aliased the foo template name to the result field } void main() { writeln( foo!(4) ); // no need to explicitly use .result here } This is very handy when you're only interested in getting one field of a template. Now let's see how unaryFunImpl works. Line 45: This is a *compile-time* check. It tries to determine if the fun argument is a string. There's an else clause way down on line 98, which, in case the fun argument isn't a string, simply aliases the fun argument to the name 'result'. So, why do we need to check if the 'fun' argument is a string? Well, because 'fun' in the template signature of unaryFunImpl is defined as an 'alias' type. An alias is a parameter type that can be a string, a value, a type, a function, or any other valid D symbol name. The reason alias is used in unaryFunImpl is because we can call unaryFunImpl in different ways. In our own code we've used: void main() { alias unaryFun!("(a & 1) == 0") isEven; } In this case the 'static if' check on line 45 will pass since the argument is a string. But we could have called unaryFun like so: void foo(int x) { } void main() { alias unaryFun!(foo) isEven; } In this case we're passing a function parameter at compile time. The 'static if' check will evaluate to false since the fun parameter is an actual function, not a string. This brings us to the else clause on line 98. Since the whole purpose of unaryFun is to construct a function out of a string, it
Re: How can you read and understand the source of *naryFun in functional.d?
P.S. Tom, I'm writing an explanation on how unaryFunImpl works right now, but it's long. Give me a few more minutes and it'll be done. :)
Re: How can you read and understand the source of *naryFun in functional.d?
Andrei, I think there's a lurking bug in unaryFunImpl, on line 53: enum testAsExpression = "{ ElementType "~parmName ~"; return ("~fun~");}()"; enum testAsStmts = "{"~ElementType.stringof ~" "~parmName~"; "~fun~"}()"; Notice the second enum, I think it's missing a ";" after "~fun~". It might need changing the last chars from "}()"; to ";}()"; That enum is never used in code which explains why the typo hasn't been caught yet.
Re: How can you read and understand the source of *naryFun in functional.d?
Tom napisał: > I am learning D for some time. I come from background of C, C# and Python. > When I saw the ways to use std.algorithem's functions, I have noticed that the > input lambda's can be writen as strings. Somewhat like the pythonic "exec". I > went to the source of this feature in functional.d > ("https://github.com/D-Programming-Language/phobos/blob/master/std/functional.d";). > The functions unaryFun and binaryFun. Is there a way I can read them and > understand them easily? or maybe I missed something? The standard library implementation must cater for a lot of corner-cases. But the essence is this: template binaryFun(string expr) { auto binaryFun(T, U)(T a, U b) { return mixin(expr); } } unittest { assert (binaryFun!"a+b"(1,2) == 3); assert (binaryFun!"a-b"(1,2) == -1); } The magic happens at the mixin line. It takes any expression or statement in string form and compiles it in context of the function. Unlike pythonic exec, the string must be known at compile-time. -- Tomek
Re: How can you read and understand the source of *naryFun in functional.d?
Tom: > The functions unaryFun and binaryFun. Is there a way I can read them and > understand them easily? or maybe I missed something? If you learn D well, you will be able to read them. But even if you know D they aren't easy to read. It's not easy stuff, that's standard-library-grade material :-) Bye, bearophile
How can you read and understand the source of *naryFun in functional.d?
Hi, I am learning D for some time. I come from background of C, C# and Python. When I saw the ways to use std.algorithem's functions, I have noticed that the input lambda's can be writen as strings. Somewhat like the pythonic "exec". I went to the source of this feature in functional.d ("https://github.com/D-Programming-Language/phobos/blob/master/std/functional.d";). The functions unaryFun and binaryFun. Is there a way I can read them and understand them easily? or maybe I missed something?