On Tue, 2003-10-28 at 22:24, Hiroshi Shinohara wrote: ... > I have another question with generator. > A few weeks ago I wrote a program to generate column numbers > like MS Excel (A,B,..,Z,AA,AB,..IV). > > It worked as I expected and made me think > "a generator can be put as a argument of a procedure".
A generator is just an expression, so you could rephrase the above as "an expression can be used as an argument to a procedure" and be equally correct. Perhaps the behavior is clearer if you do think of this way. The expression gets evaluated and produces a result that is then passed as a parameter in the procedure call. If the procedure fails, then that expression is backtracked into by GDE to see if it can produce (generate) another result. If it can, that that result is passed as a parameter in the procedure call. Similarly, 'every' can be used to force backtracking. So, in your example below, you're not passing the generator to the procedure, but rather a single result from evaluating that generator (expression). The every is forcing backtracking. > #################### > # generator of column numbers like MS Excel (A,B,..X,AA,AB,..,IV) > #################### > # gentest4.icn > procedure main() > every s := linegw(right(msperm(&ucase,1 to 2) \256,2) | &null) do write(s) > end > > #################### > # permutation generator > #################### > # arg [1]: s string : seed > # [2]: m integer : size of string > # value: string > # Usage: every ss := msperm(s,m) do ... > # ("abc",2) -> "aa","ab","ac","ba","bb","bc","ca","cb","cc" > procedure msperm(s,m) > /m := *s > if m = 0 then return "" > suspend !s || msperm(s,m-1) > end > > #################### > # words to one line generator > #################### > # arg [1]: string (word generator stopper: &null) > # [2]: integer (screen or paper width) > # [3]: string (delimiter) > # value : string (line) > # Usage : every s := linegw(gen() | &null,n_limit,s_delim) do .. > procedure linegw(s_gen,n_limit,s_delim) > static s_buf > initial s_buf := "" > /n_limit := 79 > /s_delim := " " > > if \s_gen then { > if (*s_buf + *s_delim + *s_gen) > n_limit then { > if *s_buf > 0 then { > suspend s_buf do s_buf := "" > } > } > s_buf ||:= if *s_buf = 0 then s_gen else s_delim || s_gen > } > > else if *s_buf > 0 then suspend s_buf do s_buf := "" > > end ... > every s := linegw(right(msperm(&ucase,1 to 2) \256,2) | &null) do write(s) > This looks like > msperm has a generator 1 to 2 as a argument > right has a generator msperm as a argument > linegw has a generator right(generator) | &null as a argument > > How this program works as I expect? This works because linegw() is written to work when passed pieces of the output (one label at a time). Internally, each call to linegw() takes a single label and adds it to an 'output' string, which is written (and cleared) whenever it gets long enough. Since the every is forcing msperm() to procedure all of its results, you're calling linegw() 257 times to handle the output. You're also using &null as a flag value to linegw() can figure out that there are no more calls coming and so it is time to output the last output line fragment. (Remember I said in an earlier post that a procedure can't tell when an argument that is a generator has no more results? Well, you've gotten around that by using the &null flag.) By the way, here's a slightly different approach - which trades memory for simpler code: procedure main() s := "" every s ||:= right(msperm(&ucase, 1 to 2)\256, 2) || " " outLines(s) end procedure msperm(s,m) /m := *s if m = 0 then return "" suspend !s || msperm(s,m-1) end procedure outLines(s, n_limit:78) s ? { while not pos(0) do { write(move(n_limit) | tab(0)) } } return end While this particular problem isn't as good a fit, you could also use co-expressions (in this example, via a PDCO) to avoid building up a long string: procedure main() outLines{right(msperm(&ucase, 1 to 2)\256, 2)} end procedure msperm(s,m) /m := *s if m = 0 then return "" suspend !s || msperm(s,m-1) end procedure outLines(L) nextLabel := L[1] delim := [EMAIL PROTECTED] | " " width := [EMAIL PROTECTED] | 78 n := 0 while label := @nextLabel do { w := *label + *delim if n+w > width then { write() n := 0 } writes(label,delim) n +:= w } if n > 0 then write() return end This probably isn't much (if any!) cleaner than your original approach. However, it does remove the requirement of needed an 'end' (&null) flag. -- Steve Wampler -- [EMAIL PROTECTED] Quantum materiae materietur marmota monax si marmota monax materiam possit materiari? ------------------------------------------------------- This SF.net email is sponsored by: SF.net Giveback Program. Does SourceForge.net help you be more productive? Does it help you create better code? SHARE THE LOVE, and help us help YOU! Click Here: http://sourceforge.net/donate/ _______________________________________________ Unicon-group mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/unicon-group