www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Operators as function arguments?

reply Falk Henrich <schreibmalwieder hammerfort.de> writes:
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
Mar 23 2007
next sibling parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
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
Mar 23 2007
parent Falk Henrich <schreibmalwieder hammerfort.de> writes:
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
Mar 24 2007
prev sibling next sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
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/
Mar 23 2007
parent Falk Henrich <schreibmalwieder hammerfort.de> writes:
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/
Mar 24 2007
prev sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"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..
Mar 24 2007
parent Daniel Keep <daniel.keep.lists gmail.com> writes:
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/
Mar 24 2007