How many HOFs in Phobos?

spir denis.spir at gmail.com
Wed Feb 2 03:17:22 PST 2011


On 02/02/2011 02:17 AM, bearophile wrote:
> But there are other HOFs that may be useful (they are in dlibs1 too):
>
> - "nest" (or iterate), to apply one function many times:
> nest(sin, 0.2, 4) === sin(sin(sin(sin(0.2))))

'iterate' would be great if it didn't have a different meaning in programming 
already.

> - Something similar, that keeps all the intermediate results. It's sometimes named nestList, but in D it may be lazy.

Nice to compute (math) series, I guess. What other uses?
Anyway, both are replaced by one line of D, don't you think?

> There is another problem, shown by std.functional.compose. See the part about D here:
> http://rosettacode.org/wiki/First-class_functions#D
>
> This task asks things like (more details on the rosettacode page):
> - Create new functions from preexisting functions at run-time
> - Store functions in collections
> - Use functions as arguments to other functions
> - Use functions as return values of other functions
>
>
> To do it "well enough" the D implementation doesn't want to use std.functional.compose and defines a more dynamic one, able to use run time delegates:
>
>
> private import std.math ;
> import std.stdio ;
>
> T delegate(S) compose(T, U, S)(T delegate(U) f, U delegate(S) g) {
>      return (S s) { return f(g(s)); };
> }

Great! That's the signature I would expect. Except for S U T in that order ;-) 
(what the f**k?)

Output delegate(Input) compose(Output, Median, Input)
   (Output delegate(Median) f, Median delegate(Input) g) {
     return (Input input) { return f(g(input)); };
}

> void main() {
> 	// warper need as not all built-in real functions
> 	// have same signature , eg pure/nothrow
> 	auto sin  = delegate (real x) { return std.math.sin(x) ; } ;
> 	auto asin = delegate (real x) { return std.math.asin(x) ; } ;
> 	auto cos  = delegate (real x) { return std.math.cos(x) ; } ;
> 	auto acos = delegate (real x) { return std.math.acos(x) ; } ;
> 	auto cube = delegate (real x) { return x*x*x ; } ;
> 	auto cbrt = delegate (real x) { return std.math.cbrt(x) ; } ;
>
> 	// built-in : sin/cos/asin/acos/cbrt user:cube
> 	auto fun = [sin,  cos,  cube] ;
> 	auto inv = [asin, acos, cbrt] ;
>
> 	foreach(i, f ; fun)
> 		writefln("%6.3f", compose(f, inv[i])(0.5)) ;
> }

That's the way it must be written, imo.

> You are able to write a similar program with std.functional.compose too, but using tuples instead of arrays, this is less flexible:
>
> import std.stdio, std.typetuple, std.functional;
> private import std.math;
>
> void main() {
>      // wrappers needed as not all built-in functions
>      // have same signature, eg pure/nothrow
>      auto sin  = (real x) { return std.math.sin(x); };
>      auto asin = (real x) { return std.math.asin(x); };
>      auto cos  = (real x) { return std.math.cos(x); };
>      auto acos = (real x) { return std.math.acos(x); };
>      auto cube = (real x) { return x ^^ 3; };
>      auto cbrt = (real x) { return std.math.cbrt(x); };
>
>      alias TypeTuple!(sin,  cos,  cube) dir;
>      alias TypeTuple!(asin, acos, cbrt) inv;
>
>      foreach (i, f; dir)
>          writefln("%6.3f", compose!(f, inv[i])(0.5));
> }
>
>
> This questions the design of std.functional.compose.

I do agree. Maybe of various other funcs and HOF's in stdlib as well.
In particular, I think tuple and TypeTuple shoudl not be used by other features 
in Phobos, at least as long as they are not builtin features. Their 
manipulation complicates and obscures everything. Better to use instead arrays 
for collections, or structs as named tuples. Even if a struct must be defined 
for a single use: it's clear, simple, self-documenting thank to names; and 
well-known by everyone.

Denis
-- 
_________________
vita es estrany
spir.wikidot.com



More information about the Digitalmars-d mailing list