View mode: basic / threaded / horizontal-split · Log in · Help
June 27, 2007
binding arbitrary function arguments
Hello!

I'm trying to familiarize myself a bit with D translating idioms I'm used to from other languages. Binding function arguments I ran into a problem.

Is there a "good" way to bind an arbitrary function argument?
I implemented "bind1st", "bind2nd", ... which was not too difficult, but failed when trying to implement "bindNth". Well, that is I managed to write only a rather "ugly" version:
Given for example
 int plus(int a1, int a2)...
I can do
 auto plus_four = bind1st(&plus, 4);
 plus_four(1); // => 5
but I cannot think of a way to achieve
 auto plus_four = bindNth(&plus, 1, 4); // binding first argument to 4
 plus_four(1); 

All I got so far is:
 auto plus_four = bind!(1).Nth(&plus, 4);

Any suggestions would be very welcome.
Thanks in advance,
Thomas


The code:
template bind(int I)
{
	R delegate(U) Nth(R, A, U...)(R delegate(A, U) dg, A arg)
	{
		struct binder
		{
			R delegate(A, U) dg_m;
			A arg_m;

			R call(U u)
			{
				return dg_m(u[0..I-1], arg_m, u[I-1..u.length]);
			}
		}
	
		binder* b = new binder;
		b.dg_m = dg;
		b.arg_m = arg;
		return &b.call;
	}
}
June 27, 2007
Re: binding arbitrary function arguments
Thomas wrote:
> Hello!
> 
> I'm trying to familiarize myself a bit with D translating idioms I'm used to from other languages. Binding function arguments I ran into a problem.
> 
> Is there a "good" way to bind an arbitrary function argument?

Yes! Use std.bind:
http://www.digitalmars.com/d/phobos/std_bind.html

-- 
Kirk McDonald
http://kirkmcdonald.blogspot.com
Pyd: Connecting D and Python
http://pyd.dsource.org
June 27, 2007
Re: binding arbitrary function arguments
> > Is there a "good" way to bind an arbitrary function argument?
> 
> Yes! Use std.bind:
> http://www.digitalmars.com/d/phobos/std_bind.html
> 
Thanks for the suggestion.
Actually I was aware of std.bind. But it does not seem to be capable of binding more than 10 arguments. 

Well, before I get told that I probably shouldn't use more than ten arguments I should maybe mention that I'm principally interested in learning D. That is I'd like to know if and how this general, "unlimited" binding can be done in D.
(For all practical purposes I agree that it's likely not relevant - but for understanding and learning the language it may be.)

Thomas
June 28, 2007
Re: binding arbitrary function arguments
Thomas wrote:
>>> Is there a "good" way to bind an arbitrary function argument?
>> Yes! Use std.bind:
>> http://www.digitalmars.com/d/phobos/std_bind.html
>>
> Thanks for the suggestion.
> Actually I was aware of std.bind. But it does not seem to be capable of binding more than 10 arguments. 
> 
> Well, before I get told that I probably shouldn't use more than ten arguments I should maybe mention that I'm principally interested in learning D. That is I'd like to know if and how this general, "unlimited" binding can be done in D.
> (For all practical purposes I agree that it's likely not relevant - but for understanding and learning the language it may be.)
> 
> Thomas
> 
> 
> 
> 

Why not open bind.d and look at the source?  dmd/src/phobos/std/bind.d, 
or something similar to that.
June 28, 2007
Re: binding arbitrary function arguments
Ohh this is a good one!!
bind.d(32): function bind.fnc (int,char,bool,int[],float) does not match 
parameter types ((int, char, bool, int[], float))

BTW this almost does arbitrary binding.

|template T(t...){alias t T;}
|
|template Args(A...)
|{
|  template Become(V...)
|  {
|    static assert(A.length == V.length);
|    template For(alias fn)
|    {
|      static if(
|        is(typeof(fn) arg == function) &&
|        is(typeof(fn) R   == return)
|        )
|      {
|        alias Remove!(A).From!(arg) pArgs;
|        static const uint vl = V.length;
|        alias Remove!(A).From!(range!(0,vl)) map;
|
|        R For(pArgs p)
|        {
|          arg set;
|          foreach(uint i, v; A)
|          {
|            set[A[i]] = V[i];
|          }
|
|          foreach(uint i, v; map)
|          {
|            set[map[i]] = p[i];
|          }
|
|          return fn(arg);    // line 34
|        }
|      }
|      else
|        static assert(false);
|    }
|  }
|}
|
|template Remove(R...)
|{
|  template From(A...)
|  {
|    static if(A.length != 0)
|    {
|      static if(isIn!(A.length-1, R))
|        alias Remove!(R).From!(A[0..$-1]) From;
|      else
|        alias T!(Remove!(R).From!(A[0..$-1]), A[$-1]) From;
|    }
|    else
|      alias T!() From;
|
|  }
|}
|
|template isIn(A...)
|{
|  static assert(A.length != 0);
|  static if(A.length == 1)
|    const bool isIn = false;
|  else
|  {
|    static if(A[0] == A[$-1])
|      const bool isIn = false;
|    else
|      const bool isIn = isIn!(A[0], A[1..$-1]);
|  }
|}
|
|template range(int start, int stop, A...)
|{
|  static if(start >= stop) 
|    alias T!(A,start) range;
|  else
|    alias range!(start+1, stop, A, start) range;
|}
|
|
|import std.stdio;
|
|int fnc(int that, char has, bool lots, int[] of, float args)
|{
|  writef("%s, %s, %s, %s, %s\n",that,has,lots,of,args);
|  return 0;
|}
|
|void f(int i, char c, float f) { writef("%s, %s, %s\n", i,c,f); }
|
|void main()
|{
|  alias  Args!  (0,2,   4).
|    Become!(1,true,1e7).
|    For!(fnc) fn2;
|  fn2();
|
|  alias T!(int, char, float) A;
|  A a;
|  a[0] = 0;  a[1] = 'c';  a[2] = 1e5;
|  f(a);
|}
July 05, 2007
Re: binding arbitrary function arguments
Reply to Benjamin,

> Ohh this is a good one!!
> bind.d(32): function bind.fnc (int,char,bool,int[],float) does not
> match
> parameter types ((int, char, bool, int[], float))
> BTW this almost does arbitrary binding.
> 

I am a compleat idiot!!! I was trying to pass a type tuple to a function. 
Obviously that shouldn't work!!!

(p.s. the message isn't that helpful, something like "can't pass non value 
parameters to function" would be nice)


This works

>import std.stdio;
>
>int fnc(int that, char has, bool lots, int[] of, float args)
>{
>   writef("%s, %s, %s, %s, %s\n",that,has,lots,of,args);
>   return 0;
>}
>
>void main()
>{
>   alias   Args!  (0,2,   4).
>      Become!(1,true,1e7).
>      For!(fnc).Gives fn2;
>   fn2('c', [1,2,3]);
>}
>
>
>template T(t...){alias t T;}
>
>template Args(A...)
>{
>   template Become(V...)
>   {
>      static assert(A.length == V.length);
>      template For(alias fn)
>      {
>         static if(
>            is(typeof(fn) arg == function) &&
>            is(typeof(fn) R   == return)
>            )
>         {
>            alias Remove!(A).From!(arg) pArgs;
>            static const uint vl = V.length;
>            alias range!(0,vl) imap;
>            alias Remove!(A).From!(imap) map;
>
>            R Gives(pArgs p)
>            {
>               arg set;
>               foreach(uint i, v; A)
>               {
>                  set[A[i]] = V[i];
>               }
>
>               foreach(uint i, v; map)
>               {
>                  set[map[i]] = p[i];
>               }
>
>               return fn(set);      // line 34
>            }
>         }
>         else
>            static assert(false);
>      }
>   }
>}
>
>
>template Remove(R...)
>{
>   template From(A...)
>   {
>      static if(A.length != 0)
>      {
>         static if(isIn!(A.length-1, R))
>         {
>            alias Remove!(R).From!(A[0..$-1]) From;
>         }
>         else
>         {
>            alias T!(Remove!(R).From!(A[0..$-1]), A[$-1]) From;
>         }
>      }
>      else
>      {
>         alias T!() From;
>      }
>
>   }
>}
>
>template isIn(A...)
>{
>   static assert(A.length != 0);
>
>   static if(A.length == 1)
>      const bool isIn = false;
>   else
>   {
>      static if(A[0] == A[$-1])
>         const bool isIn = true;
>      else
>         const bool isIn = isIn!(A[0], A[1..$-1]);
>   }
>}
>
>template range(int start, int stop, A...)
>{
>   static if(start >= stop) 
>      alias T!(A,start) range;
>   else
>      alias range!(start+1, stop, A, start) range;
>}
Top | Discussion index | About this forum | D home