Thread overview
Operators as function arguments?
Mar 23, 2007
Falk Henrich
Mar 24, 2007
Falk Henrich
Mar 24, 2007
Daniel Keep
Mar 24, 2007
Falk Henrich
Mar 25, 2007
Daniel Keep
March 23, 2007
Hi!

I'm trying to do some functional programming in D and came across the following problems:

Can I somehow use the built-in operator ~ as an argument to a function? The doc [1] seems to say no as operator overloading is implemented by adding a non-static member function to some class.

It would avoid lots of repetitive definitions of anonymous delegates. The following example uses reduce from [2]:

int[][] a; int[] b;
b = reduce(a, (int[] x, int[] y){return x~y;});

Now it would be useful to do

b = reduce(a,~);

It would be even nicer to define "flatten" using templates to avoid code duplication for different types of arrays. I tried to define

T[] cat(T)(T[] a, T[] b) { return a ~ b; }

but then

b = reduce(a, &cat);

yields

cat(T) is not an lvalue

The only workaround seems to be to explicitly instantiate the template function:

alias cat!(int) catInt;
b = reduce(a, &catInt);

But this is extremely clumsy. Any idea?

Falk


[1] http://www.digitalmars.com/d/operatoroverloading.html
[2] http://www.prowiki.org/wiki4d/wiki.cgi?DanielKeep/functools
March 23, 2007
Falk Henrich wrote:
> Hi!
> 
> I'm trying to do some functional programming in D and came across the
> following problems:
> 
> Can I somehow use the built-in operator ~ as an argument to a function? The
> doc [1] seems to say no as operator overloading is implemented by adding a
> non-static member function to some class.
> 
> It would avoid lots of repetitive definitions of anonymous delegates. The
> following example uses reduce from [2]:
> 
> int[][] a; int[] b;
> b = reduce(a, (int[] x, int[] y){return x~y;});
> 
> Now it would be useful to do
> 
> b = reduce(a,~);
> 
> It would be even nicer to define "flatten" using templates to avoid code
> duplication for different types of arrays. I tried to define
> 
> T[] cat(T)(T[] a, T[] b) { return a ~ b; }
> 
> but then
> 
> b = reduce(a, &cat);
> 
> yields
> 
> cat(T) is not an lvalue
> 
> The only workaround seems to be to explicitly instantiate the template
> function:
> 
> alias cat!(int) catInt;
> b = reduce(a, &catInt);
> 
> But this is extremely clumsy. Any idea?
> 
> Falk
> 
> 
> [1] http://www.digitalmars.com/d/operatoroverloading.html
> [2] http://www.prowiki.org/wiki4d/wiki.cgi?DanielKeep/functools

None, frankly.  Although, with the upcoming macros feature, you might be able to do something like this:

macro binop (Type, Op) {
  (Type x, Type y) { return x Op y; }
}

b = reduce(a, binop(int[], ~));

Although, heck, you might be able to write reduce itself as a macro passing the operator you want to it then.

macro reduce (Val, Op) {
  //...
}

b = reduce(a, ~);

Which, come to think of it, is basically what you wanted in the first place!...except that it isn't, because macros are always inlined.  Best I could come up with off the top my head, though, and reliant on as yet unreleased features.

-- Chris Nicholson-Sauls
March 24, 2007

Falk Henrich wrote:
> Hi!
> 
> I'm trying to do some functional programming in D and came across the following problems:
> 
> Can I somehow use the built-in operator ~ as an argument to a function? The doc [1] seems to say no as operator overloading is implemented by adding a non-static member function to some class.
> 
> It would avoid lots of repetitive definitions of anonymous delegates. The following example uses reduce from [2]:
> 
> int[][] a; int[] b;
> b = reduce(a, (int[] x, int[] y){return x~y;});
> 
> Now it would be useful to do
> 
> b = reduce(a,~);
> 
> It would be even nicer to define "flatten" using templates to avoid code duplication for different types of arrays. I tried to define
> 
> T[] cat(T)(T[] a, T[] b) { return a ~ b; }
> 
> but then
> 
> b = reduce(a, &cat);
> 
> yields
> 
> cat(T) is not an lvalue
> 
> The only workaround seems to be to explicitly instantiate the template function:
> 
> alias cat!(int) catInt;
> b = reduce(a, &catInt);
> 
> But this is extremely clumsy. Any idea?
> 
> Falk

Like Chris said, there's really no way to get what you want in this case.  D is not Haskell, so we just have to make lots of delegates :P

Way back when I first started using D, I actually wrote up a bunch of templates that defined delegates for every unary and binary operator, and a bunch of templated tests (like less-than, equal-to, etc.).

Re: your cat template above, you should be able to do this:

b = reduce(a, &cat!(int));

Which saves you from having to define the alias.

Also as Chris said, macros may save the day, but they will likely be a while in coming: D2.0 is looking bigger and bigger every day :P

The way I look at functional programming in D is basically: It's not as good as a *real* functional programming language, but boy does it beat the pants off C/C++/Java/C#/etc.!

Anyway, hope this helps some.

> [1] http://www.digitalmars.com/d/operatoroverloading.html
> [2] http://www.prowiki.org/wiki4d/wiki.cgi?DanielKeep/functools

Oh, you have no idea how much of a kick it is to see that link.  ^_^

	-- Daniel

-- 
int getRandomNumber()
{
    return 4; // chosen by fair dice roll.
              // guaranteed to be random.
}

http://xkcd.com/

v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP  http://hackerkey.com/
March 24, 2007
Chris Nicholson-Sauls wrote:
> None, frankly.  Although, with the upcoming macros feature, you might be able to do something like this:
> 
> macro binop (Type, Op) {
>    (Type x, Type y) { return x Op y; }
> }

That would be a killer feature that's useful for a lot more than my "operator as argument" problem.

Falk

March 24, 2007
Daniel Keep wrote:

> Like Chris said, there's really no way to get what you want in this case.  D is not Haskell, so we just have to make lots of delegates :P

I agree although I actually don't know Haskell that much, only Opal ([1]).

> Way back when I first started using D, I actually wrote up a bunch of templates that defined delegates for every unary and binary operator, and a bunch of templated tests (like less-than, equal-to, etc.).

That's what I'm doing now. It's like a yoga ;-)

> Re: your cat template above, you should be able to do this:
> b = reduce(a, &cat!(int));

Thanks. That makes the thing a bit less wordy.

> The way I look at functional programming in D is basically: It's not as good as a *real* functional programming language, but boy does it beat the pants off C/C++/Java/C#/etc.!

True. I think the ability to mix different paradigms in D is really good. None of the pure functional languages will get widely accepted as there's no decent I/O. On the other hand, things like HOF reduce code length and bugginess by a factor. So it's a really good idea to get the good stuff from FP without restricting to it.

>> [2] http://www.prowiki.org/wiki4d/wiki.cgi?DanielKeep/functools
> 
> Oh, you have no idea how much of a kick it is to see that link.  ^_^

It's a good example for D's "static if" and similar features.

Falk


[1] http://uebb.cs.tu-berlin.de/~opal/
March 24, 2007
"Falk Henrich" <schreibmalwieder@hammerfort.de> wrote in message news:eu1cm8$k2i$1@digitalmars.com...
>
> But this is extremely clumsy. Any idea?
>

Perhaps?

typeof(a[0]) reduce(alias a, alias func)()
{
    auto ret = a[0];

    foreach(v; a[1 .. $])
        ret = func(ret, v);

    return ret;
}

T[] cat(T)(T[] a, T[] b)
{
    return a ~ b;
}

void main()
{
    int[][] a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
    int[] b;

    b = reduce!(a, cat)();
    writefln(b);
}

Using the alias parameter for the function means you can no longer use delegate literals for the function, but..


March 25, 2007

Jarrett Billingsley wrote:
> "Falk Henrich" <schreibmalwieder@hammerfort.de> wrote in message news:eu1cm8$k2i$1@digitalmars.com...
>> But this is extremely clumsy. Any idea?
>>
> 
> Perhaps?
> 
> typeof(a[0]) reduce(alias a, alias func)()
> {
>     auto ret = a[0];
> 
>     foreach(v; a[1 .. $])
>         ret = func(ret, v);
> 
>     return ret;
> }
> 
> T[] cat(T)(T[] a, T[] b)
> {
>     return a ~ b;
> }
> 
> void main()
> {
>     int[][] a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
>     int[] b;
> 
>     b = reduce!(a, cat)();
>     writefln(b);
> }
> 
> Using the alias parameter for the function means you can no longer use delegate literals for the function, but..

Interesting.  I'd never thought of doing it that way. :)

I do actually use the delegate literals in a few places, tho, so it
would likely annoy me... plus, having !(...)() looks hackish. :P

	-- Daniel

-- 
int getRandomNumber()
{
    return 4; // chosen by fair dice roll.
              // guaranteed to be random.
}

http://xkcd.com/

v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP  http://hackerkey.com/