www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - binding arbitrary function arguments

reply Thomas <thomas.h ya.com> writes:
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;
	}
}
Jun 27 2007
next sibling parent reply Kirk McDonald <kirklin.mcdonald gmail.com> writes:
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
Jun 27 2007
parent reply Thomas <thomas.h ya.com> writes:
 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
Jun 27 2007
parent Jason House <jason.james.house gmail.com> writes:
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.
Jun 27 2007
prev sibling parent reply BCS <ao pathlink.com> writes:
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);
|}
Jun 28 2007
parent BCS <ao pathlink.com> writes:
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;
}
Jul 05 2007