www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - deducing Template Tuple Parameters

reply "Im, Jihyuk" <icedac g-nospam-mail.com> writes:
I saw the Curry example in http://www.digitalmars.com/d/2.0/template.html

"source.1"
[code]
import std.stdio;

/* R is return type
 * A is first argument type
 * U is TypeTuple of rest of argument types
 */
R delegate(U) Curry(R, A, U...)(R delegate(A, U) dg, A arg)
{
    struct Foo
    {
	typeof(dg) dg_m;
	typeof(arg) arg_m;

	R bar(U u)
	{
	    return dg_m(arg_m, u);
	}
    }

    Foo* f = new Foo;
    f.dg_m = dg;
    f.arg_m = arg;
    return &f.bar;
}

void main()
{
    int plus(int x, int y, int z)
    {
	return x + y + z;
    }

    auto plus_two = Curry(&plus, 2);
    writefln("%d", plus_two(6, 8));	// prints 16
}
[/code]




But this example use gc instead of manual delete (or RAII), I try to make it 
return functor."source.2"[code]template Curry( R, A, U... ){ class Curried 
{ public:  alias R delegate ( A, U ) Source;  Source   src_;  A     arg_; 
this( Source src, A arg )  {    src_ = src; arg_ = arg;   writefln( "Curried 
ctor" );   }  ~this()  { writefln( "Curried dtor" ); }    R opCall( U u ) 
{ return src_( arg_, u ); } }  Curried Curry( R delegate(A, U) dg, A arg ) 
{  return new Curried( dg, arg ); }}void CurryTest(){ int sum( int a, int b, 
int c ) { return a+b+c; }  writefln( "start of curry block" );    {  scope 
auto p = Curry( &sum, 1 );  writefln( "%d", p( 2, 3 ) ); // == 6    } // 
automatically p is deleted from here writefln( "end of curry 
block" );}[/code]but this code emits D:\_work\java_flash\test\test.d(206): 
template test.Curry(R,A,U...) is not a function 
templateD:\_work\java_flash\test\test.d(239): template test.Curry(R,A,U...) 
cannot deduce template function from argument types (int delegate(int a, int 
b, int c),int)it cant be deduce?actually, i modifed that code to this for 
making compiler happy"source.3"[code]class Bind1stFunctor(R, A, 
U...){public: alias R delegate ( A, U ) Source; Source   src_; A     arg_; 
this( Source src, A arg ) {  src_ = src;  arg_ = arg;  writefln( 
"Bind1stFunctor ctor" );  } ~this() {        writefln( "Bind1stFunctor 
dtor" ); }  R opCall( U u ) {  return src_( arg_, u ); }}Bind1stFunctor!(R, 
A, U ) Curry1st(R, A, U...)(R delegate(A, U) dg, A arg){ return new 
Bind1stFunctor!(R,A,U)( dg, arg );}[/code]can you tell me what's wrong with 
the second source? I just wanna make it as one template scope like 
soruce.2---http://www.xecode.com/blog2 
Jan 29 2008
parent reply "Im, Jihyuk" <icedac g-nospam-mail.com> writes:
oops for failed text format :0


I saw the Curry example in http://www.digitalmars.com/d/2.0/template.html

"source.1"
[code]
import std.stdio;

/* R is return type
 * A is first argument type
 * U is TypeTuple of rest of argument types
 */
R delegate(U) Curry(R, A, U...)(R delegate(A, U) dg, A arg)
{
    struct Foo
    {
 typeof(dg) dg_m;
 typeof(arg) arg_m;

 R bar(U u)
 {
     return dg_m(arg_m, u);
 }
    }

    Foo* f = new Foo;
    f.dg_m = dg;
    f.arg_m = arg;
    return &f.bar;
}

void main()
{
    int plus(int x, int y, int z)
    {
 return x + y + z;
    }

    auto plus_two = Curry(&plus, 2);
    writefln("%d", plus_two(6, 8)); // prints 16
}
[/code]



But this example use gc instead of manual delete (or RAII), I try to make it
return functor.

"source.2"
[code]
template Curry( R, A, U... )
{
 class Curried
 {
 public:
  alias R delegate ( A, U ) Source;
  Source   src_;
  A     arg_;

  this( Source src, A arg )
  {
   src_ = src; arg_ = arg;
   writefln( "Curried ctor" );
  }
  ~this()
  { writefln( "Curried dtor" ); }

  R opCall( U u )
  { return src_( arg_, u ); }
 }

 Curried Curry( R delegate(A, U) dg, A arg )
 {
  return new Curried( dg, arg );
 }
}

void CurryTest()
{
 int sum( int a, int b, int c ) { return a+b+c; }

 writefln( "start of curry block" );
    {
  scope auto p = Curry( &sum, 1 );
  writefln( "%d", p( 2, 3 ) ); // == 6
    } // automatically p is deleted from here
 writefln( "end of curry block" );
}
[/code]

but this code emits

D:\_work\java_flash\test\test.d(206): template test.Curry(R,A,U...) is not a 
function template
D:\_work\java_flash\test\test.d(239): template test.Curry(R,A,U...) cannot 
deduce template function from argument types (int delegate(int a, int b, int 
c),int)
it cant be deduce? actually, i modifed that code to this for making compiler 
happy



"source.3"
[code]
class Bind1stFunctor(R, A, U...)
{
public:
 alias R delegate ( A, U ) Source;
 Source   src_;
 A     arg_;

 this( Source src, A arg )
 {
  src_ = src;
  arg_ = arg;
  writefln( "Bind1stFunctor ctor" );
 }
 ~this()
 {
  writefln( "Bind1stFunctor dtor" );
 }

 R opCall( U u )
 {
  return src_( arg_, u );
 }
}

Bind1stFunctor!(R, A, U ) Curry1st(R, A, U...)(R delegate(A, U) dg, A arg)
{
 return new Bind1stFunctor!(R,A,U)( dg, arg );
}
[/code]

can you tell me what's wrong with the second source? I just wanna make it as 
one template scope like
soruce.2

---
http://www.xecode.com/blog2
Jan 29 2008
parent reply downs <default_357-line yahoo.de> writes:
[snip]

Your example doesn't work because a function template must only contain exactly
a single defined symbol that has the same name as the template.

Here's a simple functor version:

 import std.stdio, std.traits;
 

A sample function
 int add(int a, int b, int c) { return a+b+c; }
 

The initialization of T
 template Init(T) { T Init; }
 
 class CurryFunctor(C, P...) {
   C callable;
   P params;
   this(C c, P p) {
     callable = c;
     foreach (id, v; p) params[id] = v;
   }

The purpose of this is to allow a kind of automatic return type deduction. Think of this as the function body of opCall.
   const string CODE = "
     static if (is(typeof(callable(params, Init!(R))))) {
       return callable(params, rest);
     } else
       return curry(callable, params, rest);
   ";

Now we use our function body to determine the return type of opCall, by asking the question: "If our function were a function literal that took no parameters (declaring rest as a variable; this is okay because this function literal is never called), then what would its type be?"
   typeof(mixin("function(){ R rest; "~CODE~" }()")) opCall(R...)(R rest) {
     mixin(CODE);
   }
 }
 

A simple wrapper.
 CurryFunctor!(C, P) curry(C, P...)(C callable, P params) {
   return new CurryFunctor!(C, P)(callable, params);
 }
 

And examples.
 void main() {
   writefln(curry(&add, 2, 3)(5));
   writefln(curry(&add, 2)(3)(4));
 }

Have fun with it! --downs
Jan 29 2008
parent reply "Im, Jihyuk" <icedac g-nospam-mail.com> writes:
thanx for your kind reply :)

now I get to know the problem was a function template block should has one 
definition inside.
but I think if the second code works fine, I think it's useful for
listing template parameter once and use various tempalte declaration but the 
parameter deduced with parameters to
template function inside.

Indeed my third code works fine for me :) your code contains string code
evaluation and mixin that's yet tough to me as c++ programmer

But i found this simple code also emits duduction failure error

[code]
template Foo( R, A, U  )
{
 R delegate (U)  Foo( R delegate ( A, U ) dg, A a )
 {
  R Foo_( U u )
  { R i; return i; }
  return &Foo2_;
 }
}

void my_test()
{
 int plus_3( int a, int b, int c )
 {
  return a+b+c;
 }

 Foo( &plus_3, 10 );  // deduction failure
}
[/code]

in simpler function template works fine like:

[code]
R delegate (U) Foo2( R, A, U...)( R delegate ( A, U ) dg, A a )
{
 R Foo_( U u )
 { R i; return i; }
 return &Foo2_;
}
 Foo2( &plus_3, 10 );  // ok
[/code]

What's the problem? bug? or is there anything that i couldn't get yet?

"downs" <default_357-line yahoo.de> wrote in message 
news:fnncoj$2g95$1 digitalmars.com...
 [snip]

 Your example doesn't work because a function template must only contain 
 exactly a single defined symbol that has the same name as the template.

 Here's a simple functor version:

 import std.stdio, std.traits;

A sample function
 int add(int a, int b, int c) { return a+b+c; }

The initialization of T
 template Init(T) { T Init; }

 class CurryFunctor(C, P...) {
   C callable;
   P params;
   this(C c, P p) {
     callable = c;
     foreach (id, v; p) params[id] = v;
   }

The purpose of this is to allow a kind of automatic return type deduction. Think of this as the function body of opCall.
   const string CODE = "
     static if (is(typeof(callable(params, Init!(R))))) {
       return callable(params, rest);
     } else
       return curry(callable, params, rest);
   ";

Now we use our function body to determine the return type of opCall, by asking the question: "If our function were a function literal that took no parameters (declaring rest as a variable; this is okay because this function literal is never called), then what would its type be?"
   typeof(mixin("function(){ R rest; "~CODE~" }()")) opCall(R...)(R rest) 
 {
     mixin(CODE);
   }
 }

A simple wrapper.
 CurryFunctor!(C, P) curry(C, P...)(C callable, P params) {
   return new CurryFunctor!(C, P)(callable, params);
 }

And examples.
 void main() {
   writefln(curry(&add, 2, 3)(5));
   writefln(curry(&add, 2)(3)(4));
 }

Have fun with it! --downs

Jan 29 2008
next sibling parent "Im, Jihyuk" <icedac g-nospam-mail.com> writes:
there're some errata in code but maybe anybody know what's the point

below code is the right one

[code]
template Foo( R, A, U  )
{
 R delegate (U)  Foo( R delegate ( A, U ) dg, A a )
 {
  R Foo_( U u )
  { R i; return i; }
  return &Foo_;
 }
}
R delegate (U) Foo2( R, A, U...)( R delegate ( A, U ) dg, A a )
{
 R Foo2_( U u )
 { R i; return i; }
 return &Foo2_;
}
[/code]

-- 
Im, Jihyuk aka gshock
http://www.xecode.com/blog2


"Im, Jihyuk" <icedac g-nospam-mail.com> wrote in message 
news:fnov9q$sq1$1 digitalmars.com...
 thanx for your kind reply :)

 now I get to know the problem was a function template block should has one 
 definition inside.
 but I think if the second code works fine, I think it's useful for
 listing template parameter once and use various tempalte declaration but 
 the parameter deduced with parameters to
 template function inside.

 Indeed my third code works fine for me :) your code contains string code
 evaluation and mixin that's yet tough to me as c++ programmer

 But i found this simple code also emits duduction failure error

 [code]
 template Foo( R, A, U  )
 {
 R delegate (U)  Foo( R delegate ( A, U ) dg, A a )
 {
  R Foo_( U u )
  { R i; return i; }
  return &Foo2_;
 }
 }

 void my_test()
 {
 int plus_3( int a, int b, int c )
 {
  return a+b+c;
 }

 Foo( &plus_3, 10 );  // deduction failure
 }
 [/code]

 in simpler function template works fine like:

 [code]
 R delegate (U) Foo2( R, A, U...)( R delegate ( A, U ) dg, A a )
 {
 R Foo_( U u )
 { R i; return i; }
 return &Foo2_;
 }
 Foo2( &plus_3, 10 );  // ok
 [/code]

 What's the problem? bug? or is there anything that i couldn't get yet?

 "downs" <default_357-line yahoo.de> wrote in message 
 news:fnncoj$2g95$1 digitalmars.com...
 [snip]

 Your example doesn't work because a function template must only contain 
 exactly a single defined symbol that has the same name as the template.

 Here's a simple functor version:

 import std.stdio, std.traits;

A sample function
 int add(int a, int b, int c) { return a+b+c; }

The initialization of T
 template Init(T) { T Init; }

 class CurryFunctor(C, P...) {
   C callable;
   P params;
   this(C c, P p) {
     callable = c;
     foreach (id, v; p) params[id] = v;
   }

The purpose of this is to allow a kind of automatic return type deduction. Think of this as the function body of opCall.
   const string CODE = "
     static if (is(typeof(callable(params, Init!(R))))) {
       return callable(params, rest);
     } else
       return curry(callable, params, rest);
   ";

Now we use our function body to determine the return type of opCall, by asking the question: "If our function were a function literal that took no parameters (declaring rest as a variable; this is okay because this function literal is never called), then what would its type be?"
   typeof(mixin("function(){ R rest; "~CODE~" }()")) opCall(R...)(R rest) 
 {
     mixin(CODE);
   }
 }

A simple wrapper.
 CurryFunctor!(C, P) curry(C, P...)(C callable, P params) {
   return new CurryFunctor!(C, P)(callable, params);
 }

And examples.
 void main() {
   writefln(curry(&add, 2, 3)(5));
   writefln(curry(&add, 2)(3)(4));
 }

Have fun with it! --downs


Jan 29 2008
prev sibling parent reply downs <default_357-line yahoo.de> writes:
Im, Jihyuk wrote:
 thanx for your kind reply :)
 
 now I get to know the problem was a function template block should has one 
 definition inside.
 but I think if the second code works fine, I think it's useful for
 listing template parameter once and use various tempalte declaration but the 
 parameter deduced with parameters to
 template function inside.
 
 Indeed my third code works fine for me :) your code contains string code
 evaluation and mixin that's yet tough to me as c++ programmer
 
 But i found this simple code also emits duduction failure error
 
 [code]
 template Foo( R, A, U  )

Here's your problem. Since A and U are each single template parameters, they can each assume precisely _one_ type. However, if you'll look, &plus_3 is a void delegate(int, int, int). This means that A'd have to be int, U also, and ... then we still got an int left over that doesn't fit the template description. U... fixes this because it's a tuple and tuples can assume an arbitrary number of types.
 {
  R delegate (U)  Foo( R delegate ( A, U ) dg, A a )
  {
   R Foo_( U u )
   { R i; return i; }
   return &Foo2_;
  }
 }
 
 void my_test()
 {
  int plus_3( int a, int b, int c )
  {
   return a+b+c;
  }
 
  Foo( &plus_3, 10 );  // deduction failure
 }
 [/code]
 

--downs
Jan 30 2008
parent "Im, Jihyuk" <icedac g-nospam-mail.com> writes:
 template Foo( R, A, U  )

Here's your problem. Since A and U are each single template parameters, they can each assume precisely _one_ type. However, if you'll look, &plus_3 is a void delegate(int, int, int). This means that A'd have to be int, U also, and ... then we still got an int left over that doesn't fit the template description. U... fixes this because it's a tuple and tuples can assume an arbitrary number of types.

that err :) maybe my brain sometimes let me remove '...' in template arguments. anyway thank you! "downs" <default_357-line yahoo.de> wrote in message news:fnphi5$2eap$1 digitalmars.com...
 Im, Jihyuk wrote:
 thanx for your kind reply :)

 now I get to know the problem was a function template block should has 
 one
 definition inside.
 but I think if the second code works fine, I think it's useful for
 listing template parameter once and use various tempalte declaration but 
 the
 parameter deduced with parameters to
 template function inside.

 Indeed my third code works fine for me :) your code contains string code
 evaluation and mixin that's yet tough to me as c++ programmer

 But i found this simple code also emits duduction failure error

 [code]
 template Foo( R, A, U  )

Here's your problem. Since A and U are each single template parameters, they can each assume precisely _one_ type. However, if you'll look, &plus_3 is a void delegate(int, int, int). This means that A'd have to be int, U also, and ... then we still got an int left over that doesn't fit the template description. U... fixes this because it's a tuple and tuples can assume an arbitrary number of types.
 {
  R delegate (U)  Foo( R delegate ( A, U ) dg, A a )
  {
   R Foo_( U u )
   { R i; return i; }
   return &Foo2_;
  }
 }

 void my_test()
 {
  int plus_3( int a, int b, int c )
  {
   return a+b+c;
  }

  Foo( &plus_3, 10 );  // deduction failure
 }
 [/code]

--downs

Jan 30 2008