gusl: (Default)
[personal profile] gusl
One programming annoyance when writing loops is wanting to access each element of the list without passing the index, i.e. with code like: for (el in list) while simultaneously wanting to know the index without writing i=0 and i++.

I'm not aware of any solutions to this in current usage.

(no subject)

Date: 2010-04-28 03:10 am (UTC)
From: [identity profile] wjl.livejournal.com
In a sufficiently expressive language (e.g. SML), it is not difficult to get the behavior you want with a higher-order function. For example:
  local
    fun mapi_aux i f [] = []
      | mapi_aux i f (x::xs) = f (i, x) :: mapi_aux (i+1) f xs
  in
    (* mapi : (int * 'a -> 'b) -> 'a list -> 'b list *)
    fun mapi f list = mapi_aux 0 f list
  end

Now instead of for (el in list) { ... code(i, el) ... } you just say mapi (fn (i, el) => ... code(i, el) ...) list.

The Standard ML Basis has things like Array.iteri and Vector.mapi predefined:
  - Array.appi;
  val it = fn : (int * 'a -> unit) -> 'a array -> unit
  - Vector.mapi;
  val it = fn : (int * 'a -> 'b) -> 'a vector -> 'b vector

(no subject)

Date: 2010-04-28 03:16 am (UTC)
From: [personal profile] chrisamaphone
you beat me to it! i had the source for mapi in my copy buffer :)

(no subject)

Date: 2010-04-28 03:32 am (UTC)
From: [identity profile] robbat2.livejournal.com
Ruby's Enumerable mixin has an iterator called each_with_index.
http://ruby-doc.org/core/classes/Enumerable.src/M003137.html
   hash = Hash.new
   %w(cat dog wombat).each_with_index {|item, index|
     hash[item] = index
   }
   hash   #=> {"cat"=>0, "wombat"=>2, "dog"=>1}

(no subject)

Date: 2010-04-28 04:24 am (UTC)
From: [identity profile] bhudson.livejournal.com
Ruby really is japanese for python, isn't it. Achieves the same result, but uses more glyphs.

(no subject)

Date: 2010-04-28 05:18 am (UTC)
From: [identity profile] robbat2.livejournal.com
Possibly. Ruby is by no means my preferred language, but merely one where I was aware of an immediate answer to the question.

Part of one of the reasons I think there isn't a solution in common usage, is that the two access methods explicitly want you to consider the structure of the list:
for (el in list) - implies that the collection is unordered
for(int i=0;i<length(list);i++) - implies that the collection is strongly ordered.
Edited Date: 2010-04-28 05:19 am (UTC)

(no subject)

Date: 2010-04-28 12:01 pm (UTC)
From: [identity profile] en-ki.livejournal.com
Well, except Ruby's glyphs tend to be English words, while pythns_r_nly_almst

(no subject)

Date: 2010-04-29 04:17 am (UTC)
From: [identity profile] bhudson.livejournal.com
English words like {, |, %w, and =>
As opposed to whitespace.

(no subject)

Date: 2010-04-28 04:00 am (UTC)
From: [identity profile] fare.livejournal.com
In Common Lisp:
(loop :for el :in list :for i :from 0 :do ...)

(no subject)

Date: 2010-04-28 04:06 am (UTC)
From: [identity profile] fare.livejournal.com
Yes, one loop during which the index increases as the elements of the list are enumerated.

If you want to nest, you can have a (loop ...) inside a (loop ...).

(no subject)

Date: 2010-04-28 04:08 am (UTC)
From: [identity profile] fare.livejournal.com
Note that the Common Lisp LOOP facility is very nice in some ways, has somewhat extensible implementations, but has weird limitations and unniceties when you want advanced usage.

See Olin Shivers' LOOP (for Scheme) for the best LOOP story ever.

(no subject)

Date: 2010-04-28 04:13 am (UTC)
From: [identity profile] bhudson.livejournal.com
python:

for i, v in enumerate(list):
print "%2d => %s" % (i, v)

(no subject)

Date: 2010-04-28 04:17 am (UTC)
From: [identity profile] gustavolacerda.livejournal.com
<3

This really looks like the nicest solution!

Gotta love multiple assignment in one line! Sadly I only know of python and Matlab supporting this. Common Lisp does too, sort of, but not as nicely.

(no subject)

Date: 2010-04-28 04:23 am (UTC)
From: [identity profile] bhudson.livejournal.com
"Multiple assignment in one line" meaning assigning to tuples? Every language that isn't retarded does that. Sadly, most of the world uses retarded languages.

(no subject)

Date: 2010-04-28 06:01 pm (UTC)
From: [personal profile] chrisamaphone
i am genuinely curious why you think this is nicer than mapi (fn (v,i) => [code]) list?

(no subject)

Date: 2010-04-28 06:21 pm (UTC)
From: [identity profile] gustavolacerda.livejournal.com
because I don't understand the ML solution.

is "fn" like "lambda" and "=>" like the "." following a lambda?

Your one line of code above doesn't enumerate.

(no subject)

Date: 2010-04-28 07:00 pm (UTC)
From: [personal profile] chrisamaphone
yep, fn is lambda and '=>' is '.'.

it does enumerate. it applies the provided function (which takes the index as an argument) to every element of the list, and returns a list of the results. "appi" can be used if you just want to apply some effectful computation to every element, like printing it.

(no subject)

Date: 2010-04-29 04:25 am (UTC)
From: [identity profile] bhudson.livejournal.com
The writeup looked frightening. "Vector.mapi, comma, you dumbass" would have worked better than starting from first principles and then pointing out that actually you don't need to implement quite everything.

You can abbreviate the writeup even further if you're single-national Canadian.

(no subject)

Date: 2010-04-29 04:39 am (UTC)
From: [personal profile] chrisamaphone
yeah, well, maybe if some verbose jerk hadn't gone and stolen the opportunity. :P

but yeah i dunno, posting the actual implementation seems pedagogically more necessary in the ML example since a "map" call is totally bizarre-looking to someone used to seeing a loop structure.

(no subject)

Date: 2010-04-29 01:57 pm (UTC)
From: [identity profile] bhudson.livejournal.com
But if you're trying to teach someone how to write mapi (fn (x, i) => printf I'" => "S $ i x) thelist, and you're worried they won't understand that line of code, why expect they'll get any illumination out of the implementation of mapi?

This is a problem I've frequently had with CMU SML people. I'm used to a world that believes in abstraction. This method of giving the detailed implementation first is the very antithesis of abstraction.

(no subject)

Date: 2010-04-29 04:30 pm (UTC)
From: [personal profile] chrisamaphone
yeah, you make a good point. i think in this case my instincts were just wrong. i'm going to have to think about why i had them.

(no subject)

Date: 2010-04-29 05:33 pm (UTC)
From: [identity profile] wjl.livejournal.com
For me it was just truth in advertising: SML doesn't come with a List.mapi. But also, there's the point to be made that in a higher-order language, you're not tied to whatever looping constructs "come with" the language -- you can just roll your own, and people frequently do.

(no subject)

Date: 2010-04-30 04:57 am (UTC)
From: [identity profile] bhudson.livejournal.com
I suspect that's part of the difference between people who care about languages qua languages, rather than people who care about languages as problem-solving tools. Looking at it as a language, I *hate* python and its utter lack of static typechecking. As a tool, it's pretty decent - it's got a huge user community who have hit the same problems I hit, and have developed a rich set of libraries. SML isn't (sadly) even an option right now: I'm writing plugins for an application software, and for some odd reason there just isn't an SDK in SML.

(no subject)

Date: 2010-04-29 04:41 am (UTC)
From: [identity profile] wjl.livejournal.com
my apologies for being civil? :P

(no subject)

Date: 2010-04-29 04:55 am (UTC)
From: [identity profile] wjl.livejournal.com
For the record, i'm usually happy to take questions if you're happy to ask them :P

Here's a very short solution in another language you probably don't know:
  zipWith (\ i v -> ... code ...) [1..] list

Maybe Haskell is inherently more readable, though? :P This one makes creative use of laziness!

(no subject)

Date: 2010-04-29 05:10 am (UTC)
From: [identity profile] gustavolacerda.livejournal.com
I was intimidated. And I can't afford more than 2 minutes on this...

(no subject)

Date: 2010-04-29 05:19 am (UTC)
From: [identity profile] gustavolacerda.livejournal.com
IMHO

mapi (fn (i, el) => ... code(i, el) ...) list

is less elegant than

for i, v in enumerate(list):
  code(i, v)

because

* the Python fewer tokens
* in the ML, what the heck is "..." anyway?
* in the ML, one explicitly writes the lambda. One of the reasons Paul Graham invented Arc is because "lambda(x)" appears too often in Lisp.
Edited Date: 2010-04-29 05:20 am (UTC)

(no subject)

Date: 2010-04-29 01:32 pm (UTC)
From: [identity profile] wjl.livejournal.com
The "..." isn't ML -- just metasyntax for "some junk goes here".

(no subject)

Date: 2010-04-29 01:40 pm (UTC)
From: [identity profile] wjl.livejournal.com
Regarding the lambda, in ML's defense, it is at least shorter and more distinctive than LISP's. Haskell takes it to the exteme, with "\ x ->" instead of "lambda (x)". Macros for inventing new binding constructs might be nice, I suppose, but there's a trade off: if everyone invents their own syntax, nobody can read anybody else's code anymore, or even be able to tell which variables are bound.

(no subject)

Date: 2010-04-29 01:44 pm (UTC)
From: [identity profile] wjl.livejournal.com
In fact, the ML has one fewer token if you count the implicit "indent" and "unindent" tokens required by Python's syntax :)

(no subject)

Date: 2010-04-28 05:22 am (UTC)
From: [identity profile] robbat2.livejournal.com
(sorry for the multiple edits, but LJ is mangling it)
Oh, a related C (but C99 only) solution for you.
It's not so much as avoiding the assignment,
as making it very explicit what you're doing:
int main(int argc, char** argv) {
  char* A[4] = {"foo","bar","hello","world"};
  int length = 4;
  int i; char* s;
  for(i=0, s=A[i]; 
    i<length;
    i++, s=A[i]) {
    printf("%d %s\n",i,s);
  }
}
Edited Date: 2010-04-28 05:23 am (UTC)

(no subject)

Date: 2010-04-29 04:23 am (UTC)
From: [identity profile] bhudson.livejournal.com
const char *A[] = ...
int length = sizeof(A) / sizeof(*A);
for(int i = 0; i < length; ++i) {
const char *s = A[i];
...
}

(no subject)

Date: 2010-04-28 06:22 am (UTC)
From: [identity profile] simrob.livejournal.com
I would think this feature would almost be necessary in any language that pronounces "list" as "array" and pronounces "array" as "hashtable." It seems familiar from PHP:

foreach (list as $key => $value)
(do somethig)

(no subject)

Date: 2010-04-28 06:23 am (UTC)
From: [identity profile] simrob.livejournal.com
I should also say in my shame that I second William and Chris's mapi discussion, but they got there first ;-)

(no subject)

Date: 2010-04-28 07:59 am (UTC)
From: [identity profile] gfish.livejournal.com
I'm sure there is a crazy perl variable that keeps track of that, but I certainly don't know it off the top of my head.

(no subject)

Date: 2010-04-28 06:22 pm (UTC)
From: [identity profile] gustavolacerda.livejournal.com
Good to know. Unfortunately, it's perl.

(no subject)

Date: 2010-04-29 04:20 am (UTC)
From: [identity profile] bhudson.livejournal.com
$. for "while()" loops.

(no subject)

Date: 2010-04-29 01:58 pm (UTC)
From: [identity profile] bhudson.livejournal.com
There are angle brackets in the while that LJ gobbled up...

February 2020

S M T W T F S
      1
2345678
9101112131415
16171819202122
23242526272829

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags