February 14, 2007
Bill Baxter wrote:
[snip]
> I must not understand what your InterleavedIterator does then.  I'm thinking of something like:
> char[][] names = ["chuck", "barney", "bart"];
> int[] ids = [12983, 32345, 39284];
> 
> foreach (x; InterleavedIterator(names,ids)) {
>    writefln("Name=%s id=%s", x[0], x[1]);
> }

The one in Tango operates with a common type only; where perhaps you're combining the content of more than one collection (in Tango, you can populate a collection via an iterator, for example).

Combining mutliple lists of differing type is a somewhat different animal; if the lists are of differing lengths also, one might imagine all kinds of non-deterministic behaviour :)
February 14, 2007
Bill Baxter wrote:
>>> --bb
>>
>>
>> Why would it return a tuple? Would the collection content be of differing types? If not, then the InterleavedIterator would likely have an opApply() for use in the foreach? That's how the Tango one operates, fwiw.
> 
> 
> I must not understand what your InterleavedIterator does then.  I'm thinking of something like:
> char[][] names = ["chuck", "barney", "bart"];
> int[] ids = [12983, 32345, 39284];
> 
> foreach (x; InterleavedIterator(names,ids)) {
>    writefln("Name=%s id=%s", x[0], x[1]);
> }
> 

And here's a partial hypothetical implementation

struct InterleavedIterator(Types...)
{
   alias GetElementTypes!(Types) ElemTypes;

   static InterleavedIterator opCall(Types arg) {
      InterleavedIterator lists = arg;
   }

   int opApply( int delegate(inout ElemTypes) body) {
       ElemTypes x;
       for(uint i=0; i<; i++) {
           foreach(j,inout L; lists) x[j] = L[i];
           int ret = body(x);
           if (ret) return ret;
       }
       return 0;
   }

   Types lists;
}

Obviously it doesn't work right now because you can't do some of those things with tuples.  But it would be nice if you could.  We're really not too far from something like that working.  Especially when inout gets sorted out.

Making tuples more powerful and general, IMHO, would have many benefits.

In the static,strongly typed functional languages like ML and haskell, lists and tuples are the core data structures.  They're pretty similar to D tuples, except in ML and haskell you can return them from functions and otherwise manipulate them as first-class entities.

--bb
February 14, 2007
Bill Baxter wrote:
> Bill Baxter wrote:
> 
>>>> --bb
>>>
>>>
>>>
>>> Why would it return a tuple? Would the collection content be of differing types? If not, then the InterleavedIterator would likely have an opApply() for use in the foreach? That's how the Tango one operates, fwiw.
>>
>>
>>
>> I must not understand what your InterleavedIterator does then.  I'm thinking of something like:
>> char[][] names = ["chuck", "barney", "bart"];
>> int[] ids = [12983, 32345, 39284];
>>
>> foreach (x; InterleavedIterator(names,ids)) {
>>    writefln("Name=%s id=%s", x[0], x[1]);
>> }
>>
> 
> And here's a partial hypothetical implementation
> 
> struct InterleavedIterator(Types...)
> {
>    alias GetElementTypes!(Types) ElemTypes;
> 
>    static InterleavedIterator opCall(Types arg) {
>       InterleavedIterator lists = arg;
>    }
> 
>    int opApply( int delegate(inout ElemTypes) body) {
>        ElemTypes x;
>        for(uint i=0; i<; i++) {
>            foreach(j,inout L; lists) x[j] = L[i];
>            int ret = body(x);
>            if (ret) return ret;
>        }
>        return 0;
>    }
> 
>    Types lists;
> }
> 
> Obviously it doesn't work right now because you can't do some of those things with tuples.  But it would be nice if you could.  We're really not too far from something like that working.  Especially when inout gets sorted out.
> 
> Making tuples more powerful and general, IMHO, would have many benefits.
> 
> In the static,strongly typed functional languages like ML and haskell, lists and tuples are the core data structures.  They're pretty similar to D tuples, except in ML and haskell you can return them from functions and otherwise manipulate them as first-class entities.
> 
> --bb

Yes, would be wonderful if D could support Tuples in that manner :)
February 14, 2007
Kirk McDonald wrote:
> Sean Kelly wrote:
>> Derek Parnell wrote:
>>
>>> On Tue, 13 Feb 2007 17:39:46 +0100, Frits van Bommel wrote:
>>>
>>>> Andrei Alexandrescu (See Website For Email) wrote:
>>>>
>>>>> Bill Baxter wrote:
>>>>>
>>>>>> Yeh, I don't get it either.  How would that help me implement merge() from merge sort for instance?
>>>>>
>>>>> Merge bumps the iteration in both collections conditionally. The form above bumps the iteration in the two collections unconditionally, until one is finished; then it continues with the other until that is finished.
>>>>
>>>> In other words, it doesn't :(.
>>>
>>>
>>> I imaging that the full syntax will also include this form ...
>>>
>>>   foreach (int x, i ; coll1) (int y, j ; coll2)   {
>>>    ... use i and j ...
>>>      if (somecondition)
>>>         x = ...  // To set the index back or forward to some
>>>                  // arbitary point in the array 'coll1'.
>>>   }
>>
>>
>> This currently works for built-in arrays but not for user-defined types.  Also, I think the fact that it works as all is the result of an implementation detail, not spec-defined behavior.
> 
> There's no reason a user-defined type couldn't implement this.

As Andrei mentioned, the need to decrement the value just to stay in the same location stinks :-)  In fact, I can see it being a real issue for forward-only sequences.


Sean
February 14, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> Kirk McDonald wrote:
>> Sean Kelly wrote:
>>> Derek Parnell wrote:
>>>
>>>> On Tue, 13 Feb 2007 17:39:46 +0100, Frits van Bommel wrote:
>>>>
>>>>> Andrei Alexandrescu (See Website For Email) wrote:
>>>>>
>>>>>> Bill Baxter wrote:
>>>>>>
>>>>>>> Yeh, I don't get it either.  How would that help me implement merge() from merge sort for instance?
>>>>>>
>>>>>> Merge bumps the iteration in both collections conditionally. The form above bumps the iteration in the two collections unconditionally, until one is finished; then it continues with the other until that is finished.
>>>>>
>>>>> In other words, it doesn't :(.
>>>>
>>>>
>>>> I imaging that the full syntax will also include this form ...
>>>>
>>>>   foreach (int x, i ; coll1) (int y, j ; coll2)   {
>>>>    ... use i and j ...
>>>>      if (somecondition)
>>>>         x = ...  // To set the index back or forward to some
>>>>                  // arbitary point in the array 'coll1'.
>>>>   }
>>>
>>>
>>> This currently works for built-in arrays but not for user-defined types.  Also, I think the fact that it works as all is the result of an implementation detail, not spec-defined behavior.
>>>
>>>
>>> Sean
>>
>> There's no reason a user-defined type couldn't implement this.
> 
> Exactly. Walter and I have bounced a couple of possibilities and concluded that the feature is of "medium difficulty/medium usefulness". Probably Walter will look into implementing this first:
> 
> foreach (i ; 0 .. n)
> {
>   ...
> }

Out of curiosity, how would these situations be handled:

  foreach (i ; n .. 0) {}         // A
  foreach_reverse (i ; 0 .. n) {} // B
  foreach_reverse (i ; n .. 0) {} // C

Sean
February 14, 2007
Walter Bright wrote:
> X Bunny wrote:
>> (defun ack (x y)
>>   (declare (fixnum x y))
>>   (the fixnum
>>     (if (zerop x)
>>     (1+ y)
>>       (if (zerop y)
>>       (ack (1- x) 1)
>>     (ack (1- x) (ack x (1- y)))))))
>>
>> The structure is no less obvious to me then the C. I can see the input and output types are clearly fixnums. The branches of the ifs are obvious.
> 
> I see:
>     1- x
> in the Lisp code, and have to mentally translate it to:
>     x - 1
> and not:
>     1 - x
> 
> This just hurts my brain.

I thought Lisp used prefix notation, but the above syntax looks like element composition.


Sean
February 14, 2007
X Bunny wrote:
> Kevin Bealer wrote:
>> X Bunny wrote:
>>> Kevin Bealer wrote:
>>>>
>>>> 2. The syntax doesn't provide visual hints that let you read a program.
>> What I mean, is this (from the Computer Language Shootout):
>>
>> (defun ack (x y)
>>   (declare (fixnum x y))
>>   (the fixnum
>>     (if (zerop x)
>>     (1+ y)
>>       (if (zerop y)
>>       (ack (1- x) 1)
>>     (ack (1- x) (ack x (1- y)))))))
>>
>> as compared to this:
>>
>> int Ack(int x, int y)
>> {
>>     if (x == 0) {
>>         return y + 1;
>>     } else if (y == 0) {
>>         return Ack(x-1, 1);
>>     } else {
>>         return Ack(x-1, Ack(x, y-1));
>>     }
>> }
>>
>> These two things do the same thing in the same way, but the structure and syntax make the C example much more readable.  If I want to know input and output types, I can find them.  When I see the top of the if/elseif/else structure, I can find each part.  It's layed out like a table, rather than like a ball of yarn.
> 
> If the C was indented like this would it be as unreadable as the Lisp?
> 
> int ack(int x, int y)
> {
>     if(x == 0)
>     { return y + 1; }
>         else if(y == 0)
>         { return ack(x-1, 1); }
>             else {
>                 return ack(x-1, ack(x, y-1));
>             }
> }

Yes - indenting badly makes it less readable in either case; I'm not sure if I was indenting the LISP example in a reasonable way. (I took it from someone else's page.)

> (I cant even match up all the brackets with that one!)
>        My editor indents the Lisp like this:
> 
> (defun ack (x y)
>   (declare (fixnum x y))
>   (the fixnum
>     (if (zerop x)
>     (1+ y)
>       (if (zerop y)
>       (ack (1- x) 1)
>     (ack (1- x) (ack x (1- y)))))))
> 
> The structure is no less obvious to me then the C. I can see the input and output types are clearly fixnums. The branches of the ifs are obvious.

Maybe one day it will be for me if I keep trying to do things in LISP, but I can't shake the feeling that I'm learning to shoe horses -- a skill that had its place and time.

>> More importantly, I can understand *parts* of this code without understanding the whole thing.
> 
> Mmmm I dont what to say about that, for me with the Lisp I can do the same.
> 
> Bunny

Actually, I can understand the structure in both languages for this simple example without too much trouble.  But the LISP one is a lot 'slower' for me to scan with my eyes.  Some of that is a learned reflex, of course, but personally I don't think all of it is.

My point is less about indentation than the other aspects of syntax. For one thing, the '(){};,' punctuation, which for me, is a win over the LISP way (again, assuming both examples are indented).  If the LISP syntax is readable for you throughout, then that's okay.  For me it definitely isn't -- I think most people would agree.

Someone I know at work told me today that the LISP notation is very much like mathematical formulas.  I couldn't help remembering math classes in college, when (at the time) I was always thinking, 'why can't they break this up into simple steps like a computer program would?'  (Of course, I learned a lot about programming before I took algebra, so maybe that's part of the problem.)

Kevin
February 14, 2007
Kevin Bealer wrote:

> Someone I know at work told me today that the LISP notation is very much like mathematical formulas.  I couldn't help remembering math classes in college, when (at the time) I was always thinking, 'why can't they break this up into simple steps like a computer program would?'  (Of course, I learned a lot about programming before I took algebra, so maybe that's part of the problem.)

I'm not sure what you mean.  Mathematicians (and lisp coders) are champs of breaking things into simple steps.  My problem is usually that there are *too* many simple steps so that the equation that ties it all together is a very uninformative   x = f(y)~G,  where f, y, G and the operator ~ are all things whose definitions are scattered over the previous 50 pages.

With Lisp coders it's because it's so easy to pull out any (...) expression at any level and turn it into a new function when the current function starts to get too nested.

--bb
February 14, 2007
Sean Kelly wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>> Kirk McDonald wrote:
>>> Sean Kelly wrote:
>>>> Derek Parnell wrote:
>>>>
>>>>> On Tue, 13 Feb 2007 17:39:46 +0100, Frits van Bommel wrote:
>>>>>
>>>>>> Andrei Alexandrescu (See Website For Email) wrote:
>>>>>>
>>>>>>> Bill Baxter wrote:
>>>>>>>
>>>>>>>> Yeh, I don't get it either.  How would that help me implement merge() from merge sort for instance?
>>>>>>>
>>>>>>> Merge bumps the iteration in both collections conditionally. The form above bumps the iteration in the two collections unconditionally, until one is finished; then it continues with the other until that is finished.
>>>>>>
>>>>>> In other words, it doesn't :(.
>>>>>
>>>>>
>>>>> I imaging that the full syntax will also include this form ...
>>>>>
>>>>>   foreach (int x, i ; coll1) (int y, j ; coll2)   {
>>>>>    ... use i and j ...
>>>>>      if (somecondition)
>>>>>         x = ...  // To set the index back or forward to some
>>>>>                  // arbitary point in the array 'coll1'.
>>>>>   }
>>>>
>>>>
>>>> This currently works for built-in arrays but not for user-defined types.  Also, I think the fact that it works as all is the result of an implementation detail, not spec-defined behavior.
>>>>
>>>>
>>>> Sean
>>>
>>> There's no reason a user-defined type couldn't implement this.
>>
>> Exactly. Walter and I have bounced a couple of possibilities and concluded that the feature is of "medium difficulty/medium usefulness". Probably Walter will look into implementing this first:
>>
>> foreach (i ; 0 .. n)
>> {
>>   ...
>> }
> 
> Out of curiosity, how would these situations be handled:
> 
>   foreach (i ; n .. 0) {}         // A

rewrite to: for (typeof(true ? n : 0) i = n; i < 0; ++i) {}

with the amendment that the loop body can't modify i, and that 0 is evaluated only once :o).

>   foreach_reverse (i ; 0 .. n) {} // B

rewrite to: for (typeof(true ? 0 : n) i = n; i-- > 0; ) {}

with the same amendments.

>   foreach_reverse (i ; n .. 0) {} // C

rewrite to: for (typeof(true ? 0 : n) i = 0; i-- > n; ) {}

with the amendment that the loop body can't modify i, and that n is evaluated only once.


Andrei
February 14, 2007
Kevin Bealer wrote:
> X Bunny wrote:
>> Kevin Bealer wrote:
>>> X Bunny wrote:
>>>> Kevin Bealer wrote:
>>>>>
>>>>> 2. The syntax doesn't provide visual hints that let you read a program.
>>> What I mean, is this (from the Computer Language Shootout):
>>>
>>> (defun ack (x y)
>>>   (declare (fixnum x y))
>>>   (the fixnum
>>>     (if (zerop x)
>>>     (1+ y)
>>>       (if (zerop y)
>>>       (ack (1- x) 1)
>>>     (ack (1- x) (ack x (1- y)))))))
>>>
>>> as compared to this:
>>>
>>> int Ack(int x, int y)
>>> {
>>>     if (x == 0) {
>>>         return y + 1;
>>>     } else if (y == 0) {
>>>         return Ack(x-1, 1);
>>>     } else {
>>>         return Ack(x-1, Ack(x, y-1));
>>>     }
>>> }
>>>
>>> These two things do the same thing in the same way, but the structure and syntax make the C example much more readable.  If I want to know input and output types, I can find them.  When I see the top of the if/elseif/else structure, I can find each part.  It's layed out like a table, rather than like a ball of yarn.
>>
>> If the C was indented like this would it be as unreadable as the Lisp?
>>
>> int ack(int x, int y)
>> {
>>     if(x == 0)
>>     { return y + 1; }
>>         else if(y == 0)
>>         { return ack(x-1, 1); }
>>             else {
>>                 return ack(x-1, ack(x, y-1));
>>             }
>> }
> 
> Yes - indenting badly makes it less readable in either case; I'm not sure if I was indenting the LISP example in a reasonable way. (I took it from someone else's page.)
> 
>> (I cant even match up all the brackets with that one!)
>>        My editor indents the Lisp like this:
>>
>> (defun ack (x y)
>>   (declare (fixnum x y))
>>   (the fixnum
>>     (if (zerop x)
>>     (1+ y)
>>       (if (zerop y)
>>       (ack (1- x) 1)
>>     (ack (1- x) (ack x (1- y)))))))
>>
>> The structure is no less obvious to me then the C. I can see the input and output types are clearly fixnums. The branches of the ifs are obvious.
> 
> Maybe one day it will be for me if I keep trying to do things in LISP, but I can't shake the feeling that I'm learning to shoe horses -- a skill that had its place and time.

Probably it's better comparable to harnessing a teleporting machine :o).

Andrei