Thread overview
binding arbitrary function arguments
Jun 27, 2007
Thomas
Jun 27, 2007
Kirk McDonald
Jun 27, 2007
Thomas
Jun 28, 2007
Jason House
Jun 28, 2007
BCS
Jul 05, 2007
BCS
June 27, 2007
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
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
> > 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
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
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
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;
>}