www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - ReturnType of lambda templates

reply "Roland Hadinger" <rolandh.dlangforum maildrop.cc> writes:
Hi!

Suppose I wanna do this (which already works, which is why D is 
pretty cool):

     import std.traits;
     import std.typecons : Nullable;

     // Retrofit Nullable to allow for monadic chaining
     //
     auto apply( alias fun, T )( Nullable!T nullable )
         if( isSomeFunction!fun )
     {
         enum returnsVoid     = is( ReturnType!fun == void );
         enum returnsNullable = is( ReturnType!fun : Nullable!X, X 
);

         static if( returnsVoid ) {

             if( !nullable.isNull )
                 fun( nullable.get );

         } else static if( returnsNullable ) {

             alias NR = ReturnType!fun;

             if( nullable.isNull )
                 return NR();
             else
                 return fun( nullable.get );

         } else {

             alias NR = Nullable!( ReturnType!fun );

             if( nullable.isNull )
                 return NR();
             else
                 return NR( fun( nullable.get ) );
         }
     }

     void main()
     {
         Nullable!int a = 1;
         Nullable!int b = a.apply!( (int x) => 2 * x );
                        // .apply!( (double x) => foo( x, u ) )
                        // .apply!( (double x) => bar( x, v ) )
                        // .apply!( (string x) => baz( x, w ) );
     }

...but without explicitly specifying the type of the lambda 
parameter:

     void main()
     {
         Nullable!int a = 1;
         Nullable!int b = a.apply!( x => 2 * x );
                        // .apply!( x => foo( x, u ) )
                        // .apply!( x => bar( x, v ) )
                        // .apply!( x => baz( x, w ) );
     }

Problem is, the shorter form involves lambda templates, and both 
'isSomeFunction' and 'ReturnType' currently don't seem to work
with those. No problems with the other version.

Can I fix my 'apply' function to still allow for the less verbose 
form?

If that's impossible, is it a theoretical possibility to improve 
D's type deduction to handle this?

Or should I just not attempt to write code like this for the time 
being (after all, functional code like this incurs some overhead, 
but in this particular case, I'd prefer legibility over 
performance)?

Thanks!
Aug 18 2015
parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Tuesday, 18 August 2015 at 14:25:34 UTC, Roland Hadinger wrote:
 Hi!

 Suppose I wanna do this (which already works, which is why D is 
 pretty cool):

     import std.traits;
     import std.typecons : Nullable;

     // Retrofit Nullable to allow for monadic chaining
     //
     auto apply( alias fun, T )( Nullable!T nullable )
         if( isSomeFunction!fun )
     {
         enum returnsVoid     = is( ReturnType!fun == void );
         enum returnsNullable = is( ReturnType!fun : Nullable!X, 
 X );

         static if( returnsVoid ) {

             if( !nullable.isNull )
                 fun( nullable.get );

         } else static if( returnsNullable ) {

             alias NR = ReturnType!fun;

             if( nullable.isNull )
                 return NR();
             else
                 return fun( nullable.get );

         } else {

             alias NR = Nullable!( ReturnType!fun );

             if( nullable.isNull )
                 return NR();
             else
                 return NR( fun( nullable.get ) );
         }
     }

     void main()
     {
         Nullable!int a = 1;
         Nullable!int b = a.apply!( (int x) => 2 * x );
                        // .apply!( (double x) => foo( x, u ) )
                        // .apply!( (double x) => bar( x, v ) )
                        // .apply!( (string x) => baz( x, w ) );
     }

 ...but without explicitly specifying the type of the lambda 
 parameter:

     void main()
     {
         Nullable!int a = 1;
         Nullable!int b = a.apply!( x => 2 * x );
                        // .apply!( x => foo( x, u ) )
                        // .apply!( x => bar( x, v ) )
                        // .apply!( x => baz( x, w ) );
     }

 Problem is, the shorter form involves lambda templates, and 
 both 'isSomeFunction' and 'ReturnType' currently don't seem to 
 work
 with those. No problems with the other version.

 Can I fix my 'apply' function to still allow for the less 
 verbose form?

 If that's impossible, is it a theoretical possibility to 
 improve D's type deduction to handle this?

 Or should I just not attempt to write code like this for the 
 time being (after all, functional code like this incurs some 
 overhead, but in this particular case, I'd prefer legibility 
 over performance)?

 Thanks!
for simple lambdas like that (i.e. function templates with one template arguments that corresponds to the type of the first and only argument), just add this template overload: auto apply( alias fun, T )( Nullable!T nullable ) if( !isSomeFunction!fun ) { return .apply!(fun!T, T)(nullable); } and it should work (give or a take a few typos on my part).
Aug 18 2015
parent "Roland Hadinger" <rolandh.dlangforum maildrop.cc> writes:
On Tuesday, 18 August 2015 at 15:11:34 UTC, John Colvin wrote:
 for simple lambdas like that (i.e. function templates with one 
 template arguments that corresponds to the type of the first 
 and only argument), just add this template overload:

 auto apply( alias fun, T )( Nullable!T nullable )
     if( !isSomeFunction!fun )
 {
     return .apply!(fun!T, T)(nullable);
 }

 and it should work (give or a take a few typos on my part).
That was quick - and it works :) Now, where is my thinking cap again?
Aug 18 2015