Re: Ultra-pure map()?

2013-12-29 Thread David Held

On 12/28/2013 5:13 AM, Timon Gehr wrote:

[...]
I wouldn't call this an 'eager map'. It's a shallow wrapper around a
foreach loop.


The point being that foreach loops aren't composable.

Dave



Re: Ultra-pure map()?

2013-12-29 Thread David Held

On 12/28/2013 2:07 AM, FreeSlave wrote:

[...]
If you want to get result just now, then use 'array' function from
std.array module.

map!fun(range).array;

or

array(map!fun(range));


Syntactically compact and slightly better expression of intent, but much 
less efficient than just calling reduce().


Dave



Re: Ultra-pure map()?

2013-12-29 Thread Ali Çehreli
On 12/29/2013 02:11 PM, David Held wrote: On 12/28/2013 5:13 AM, Timon 
Gehr wrote:

 [...]
 I wouldn't call this an 'eager map'. It's a shallow wrapper around a
 foreach loop.

 The point being that foreach loops aren't composable.

Agreed. However, if they were composable they would have to be at the 
end of the chain because when they don't produce a range, no other 
function can be added after them.


If we imagine a foreach that produces a range, then it becomes map.


 Dave


Ali



Re: Ultra-pure map()?

2013-12-29 Thread Timon Gehr

On 12/29/2013 11:11 PM, David Held wrote:

On 12/28/2013 5:13 AM, Timon Gehr wrote:

[...]
I wouldn't call this an 'eager map'. It's a shallow wrapper around a
foreach loop.


The point being that foreach loops aren't composable.

Dave



Wrapping it will not change that.


Re: Ultra-pure map()?

2013-12-28 Thread David Held

On 12/27/2013 7:32 PM, Marco Leise wrote: [...]
 Side effects and altering the input object itself makes me
 want to pull out my crucifix. You shall not have impurity in
 your functional style code!

Why not?  There are many impure functional languages, and most 
non-functional languages that allow functional style allow mutation. 
OOP is all about hiding state, which is the opposite of referential 
transparency.  Are you saying we should never map/fold over OOP ranges? 
 That seems like an unnecessary restriction for dogma's sake. 
Obviously, map() has to be lazy to support infinite ranges.  But I 
assume that reduce() must be eager so that you actually get a result (I 
mean, it could probably be made lazy at enormous expense, but that would 
just be silly).  So, if you want side effects, I guess you have to do 
the slightly dirty trick of calling reduce() without actually reducing 
anything.


I guess the right thing to do would be to make a new algorithm that 
implements an eager map() but perhaps doesn't bother with the result, 
called invoke().  This carries none of the semantic baggage of 
well-known pure higher-order functions, and even sounds more OOP-like. 
Most of the other features of map() (like parallel iteration) are pretty 
nice to have in eager form.


Dave



Re: Ultra-pure map()?

2013-12-28 Thread FreeSlave

On Saturday, 28 December 2013 at 09:18:00 UTC, David Held wrote:

On 12/27/2013 7:32 PM, Marco Leise wrote: [...]
 Side effects and altering the input object itself makes me
 want to pull out my crucifix. You shall not have impurity in
 your functional style code!

Why not?  There are many impure functional languages, and most 
non-functional languages that allow functional style allow 
mutation. OOP is all about hiding state, which is the opposite 
of referential transparency.  Are you saying we should never 
map/fold over OOP ranges?
 That seems like an unnecessary restriction for dogma's sake. 
Obviously, map() has to be lazy to support infinite ranges.  
But I assume that reduce() must be eager so that you actually 
get a result (I mean, it could probably be made lazy at 
enormous expense, but that would just be silly).  So, if you 
want side effects, I guess you have to do the slightly dirty 
trick of calling reduce() without actually reducing anything.


I guess the right thing to do would be to make a new 
algorithm that implements an eager map() but perhaps doesn't 
bother with the result, called invoke().  This carries none 
of the semantic baggage of well-known pure higher-order 
functions, and even sounds more OOP-like. Most of the other 
features of map() (like parallel iteration) are pretty nice to 
have in eager form.


Dave


If you want to get result just now, then use 'array' function 
from std.array module.


map!fun(range).array;

or

array(map!fun(range));


Re: Ultra-pure map()?

2013-12-28 Thread bearophile

David Held:


Why not?


Because mixing map/filter and wild unrestrained side effects is 
asking for troubles (bugs in your code).


Bye,
bearophile


Re: Ultra-pure map()?

2013-12-28 Thread Timon Gehr

On 12/28/2013 10:17 AM, David Held wrote:

On 12/27/2013 7:32 PM, Marco Leise wrote: [...]
  Side effects and altering the input object itself makes me
  want to pull out my crucifix. You shall not have impurity in
  your functional style code!

Why not?  There are many impure functional languages, and most
non-functional languages that allow functional style allow mutation. OOP
is all about hiding state, which is the opposite of referential
transparency.


That's news to me. OOP does not mandate a procedural programming style.


...
Obviously, map() has to be lazy to support infinite ranges.  ...
So, if you want side effects, I guess you have to do
the slightly dirty trick of calling reduce() without actually reducing
anything.
...


What's the point? There are cleaner ways of doing the same.

The implementation of map assumes that the result is independent of how 
it is iterated, and using it with callables that make it fail this 
criterion is usually at best confusing and at worst a bug.



I guess the right thing to do would be to make a new algorithm that
implements an eager map() but perhaps doesn't bother with the result,
called invoke().  ...


I wouldn't call this an 'eager map'. It's a shallow wrapper around a 
foreach loop.


Ultra-pure map()?

2013-12-27 Thread David Held

import std.algorithm;
import std.stdio;
import std.conv;

class Trivial
{
int sideEffect() { return n++; }
override string toString() pure { return to!string(n); }
int n;
}

void main()
{
Trivial[] objs = [ new Trivial ];
map!(o = o.sideEffect())(objs);
writeln(objs);  // [0]
foreach (o; objs) o.sideEffect();
writeln(objs);  // [1]
}

Can someone explain to me why map() is not equivalent to foreach in the 
code above?  From what I can tell, map() doesn't do anything at all on 
objs, even though it is a perfectly legitimate range (as far as I can tell).


Dave


Re: Ultra-pure map()?

2013-12-27 Thread David Nadlinger

On Saturday, 28 December 2013 at 01:41:35 UTC, David Held wrote:
Can someone explain to me why map() is not equivalent to 
foreach in the code above?  From what I can tell, map() doesn't 
do anything at all on objs, even though it is a perfectly 
legitimate range (as far as I can tell).


map() constructs a range that invokes a given function on the
source range if an element is requested – but only then. In other
words, map is fully lazy.

David


Re: Ultra-pure map()?

2013-12-27 Thread David Held

On 12/27/2013 5:46 PM, David Nadlinger wrote:

On Saturday, 28 December 2013 at 01:41:35 UTC, David Held wrote:

Can someone explain to me why map() is not equivalent to foreach in
the code above?  From what I can tell, map() doesn't do anything at
all on objs, even though it is a perfectly legitimate range (as far as
I can tell).


map() constructs a range that invokes a given function on the
source range if an element is requested – but only then. In other
words, map is fully lazy.


Functional programming was surely invented by labor unions!

Dave




Re: Ultra-pure map()?

2013-12-27 Thread John Colvin

On Saturday, 28 December 2013 at 01:41:35 UTC, David Held wrote:

import std.algorithm;
import std.stdio;
import std.conv;

class Trivial
{
int sideEffect() { return n++; }
override string toString() pure { return to!string(n); }
int n;
}

void main()
{
Trivial[] objs = [ new Trivial ];
map!(o = o.sideEffect())(objs);
writeln(objs);  // [0]
foreach (o; objs) o.sideEffect();
writeln(objs);  // [1]
}

Can someone explain to me why map() is not equivalent to 
foreach in the code above?  From what I can tell, map() doesn't 
do anything at all on objs, even though it is a perfectly 
legitimate range (as far as I can tell).


Dave


Map is lazy and is never iterated over in your code, therefore no 
side effects.


Re: Ultra-pure map()?

2013-12-27 Thread Marco Leise
Am Sat, 28 Dec 2013 01:54:26 +
schrieb John Colvin john.loughran.col...@gmail.com:

 On Saturday, 28 December 2013 at 01:41:35 UTC, David Held wrote:
  import std.algorithm;
  import std.stdio;
  import std.conv;
 
  class Trivial
  {
  int sideEffect() { return n++; }
  override string toString() pure { return to!string(n); }
  int n;
  }
 
  void main()
  {
  Trivial[] objs = [ new Trivial ];
  map!(o = o.sideEffect())(objs);
  writeln(objs);  // [0]
  foreach (o; objs) o.sideEffect();
  writeln(objs);  // [1]
  }
 
  Can someone explain to me why map() is not equivalent to 
  foreach in the code above?  From what I can tell, map() doesn't 
  do anything at all on objs, even though it is a perfectly 
  legitimate range (as far as I can tell).
 
  Dave
 
 Map is lazy and is never iterated over in your code, therefore no 
 side effects.

Yeah, this is kind of unintended usage. Typically with map you
take some input range, apply some algorithm to each element,
and return a range of the results.

Side effects and altering the input object itself makes me
want to pull out my crucifix. You shall not have impurity in
your functional style code!

-- 
Marco