Here is a major elaboration on generators (I post this as is, I have no one else whom I can ask for a proofread in any case):
'One concern with lazy evaluation is that errors may not be encountered' Yes, exactly this is an excellent point: generators must be able to guarantee their ability to generate the entire list without error, which leads us to a key point, which I feel is being overlooked here: Generators are absolutely not a replacement for evaluating all temporary arrays, they are a situatuational improvement ! There are naturally plenty of cases where holding off evaluation is detrimental: i.3 : the physical array is clearly simpler and faster than a generator u&.> : this generator has information about the whole array, but not (necessarily) about individual boxes, so perhaps this is a case where we should give up and create the array. illustration: u@v y: u asks for a cell, v produces it, and u fails on it for some reason => perhaps we overlooked an earlier error where v would have failed on a different cell. Very importantly, there is nothing lost from holding off evaluation until one is certain it is necessary: at worst, we lose a handful of processor ticks trying to hold off the inevitable, and at best, we avoid building a temporary array and open possiblities for simplifications down the line. The obstacle posed by accurate error reporting is a significant one however. For finite arrays, we can fall back to spawning arrays whenever a generator combination is unable to guarantee success. For the infinite case, perhaps the best we can do is print the error and additionally print a warning wherever a generator link was compiled that cannot guarantee correctness. However, theoretically it should be possible to predict any possible error down the line when creating a generator link. Generators are not really verbs.. they are nouns to the JFE after all, and thus have all the information necessary to be produced in their entirety, although some complications arise for subsequent generators when verifying correctness after someone asks to box parts of a generator. Again, my canonical example where I feel one must break a generator chain is when working under boxes of an existing physical array containing boxed elements. Fortunately, in this case the array is finite and we can simply create a physical array and terminate the generator train in progress, in order to check the entire noun's validity before proceeding. Let's take a look at Roger Hui's examples and his challenge (the fact the array examples are infinite force a generator approach (or at least prevent the use of physical arrays)): >a. A few interesting examples of infinite arrays: > > odd =: 1+2*i._ > even=: 2*i._ > odd e. even >0 0 0 0 0 ... > > fib0=: 0,{:"1 ]2 x: (+%)/\ _$1x > fib1=: {."1 +/\@|.^:(i._) 0 1x > *./ fib0 -: fib1 > An implementation that can do the last three sentences would be quite an > accomplishment. The first example is a good example of what generators would be exceptionally good at handling. The second however, I believe clearly exposes Raul's main concern: we cannot fallback to creating physical infinite arrays, so we must, come what may, keep working with generator chains. Generator chains then, need to be studied in depth. (his second concern: whether the time I spend implementing this could be better spent elsewhere is of absolutely no concern to me; I have the immense luxury of still being a student). So... Our generator is infinite, and we cannot fall back to conjuring it up physically. Does this mean that some operatoions are impossible, and must return a domain error? Operations must in any event be stored symbolically, so some errors may go undetected for some time (pending a rigorous proof of the following conjecture: 'we are able to either guarantee correctness for all generator links based on i._, or bail out immediately with an error'). Here is perhaps our biggest problem then: Are there any errors that cannot be predicted by a generator link on i._ ? Well, boxes aside, we should be able to see coming all syntax, rank and length errors should be predictable for any generator link, since we can analyze the complete information we have for generating the array. As a result then, we need this axiom (for a valid generator): it must guarantee it's ability to generate an array (short of system limits)). Should my conjecture about guaranteeing correctness on i._, prove false, then the offending operations on infinite generators must trigger a domain error. Let's be more concrete though, and examine the generator chain for Roger's fib0. Noting that Generators are a natural way of representing conjunctions, the process I am about to describe can be thought of as 'compiling a J sentence to a generator chain'. I write 'Gn' to designate the nth generator, counting from the right. _$1x : G1 is the constant function 1:, for any y (note it is absolutely not equivalent to 1:, the generator should be thought of as a noun (is a noun to the JFE)). \ G2 returns (i.y) {. G1 (here we could even think of simplifying directly to y$1, since G1 knows it is constant) / y { G3 is (y, 1+y) { G2 (+ %) y { G4 is given by (+%)/ y {G3 (y { G3 returns 2 Values here, and G4 is a dyadic generator) 2 x: y { G5 returns 2 x: y { G4 {:"1 y { G6 returns {:"1 y { G5 NB. Here is potentially a win, as G6 won't ask for all of G1-5 0, y { G7 is represented as a concatenation of a physical list and a generator. The last generator would usually be forced into a physical array.. this array being infinite though, I suggest eitheir laconically printing a prefix, as J usually does, or even entering an infinite loop printing loop if one uses ,. may be a valid reaction. Naturally some operations on an infinite generator must trigger a domain error: attempting to print the thing to a file comes to mind. Now we see also the dream take shape: result argument cells can be built directly from the rightmost argument! Those generators that intend to reuse argument cells can be expected to remember them, in order to avoid asking for a recalculation. (or perhaps such a generator link should force an array). 'fib1' and 'fb0 -: fb1' can be built similarly (u^:(i._) even maps very nicely to generators, the one representing ^: can readily reuse it's preceeding result) . Now the key to the 'accomplishment' lies in the pattern '*/ (generator)'. This attempt to collapse an infinite generator could of course just bail out with a domain error, but more interestingly, is there any conceivable way that this reqeust could be met ? In the specific case of boolean *./, one must somehow prove that the generator is in fact equivalent to the constant generator _$1. This suggests we need to be able to simplify generator chains. The good news is that there are no precedence issues in generator chains and J is free to rearrange commutative generators and hopefully remove those that cancel each other out. The actual problems associated with this depend on generator implementation details. If such 'J symbolic algebra' is possible, then at least a subset of such problems can be solved. J4 ________________________________ From: Source <source-boun...@forums.jsoftware.com> on behalf of Don Guinn <dongu...@gmail.com> Sent: Wednesday, February 28, 2018 5:41:51 PM To: Source forum Subject: Re: [Jsource] Propositions One concern with lazy evaluation is that errors may not be encountered until something happens to make the evaluation go beyond what has been encountered before. Particularly during development and testing. Is there a way to turn off lazy evaluation in python during development and testing? On Feb 28, 2018 8:43 AM, "Raul Miller" <rauldmil...@gmail.com> wrote: > On Wed, Feb 28, 2018 at 10:21 AM, james faure <james.fa...@epitech.eu> > wrote: > > For J, where so much more is happening per statement, we could > transparently replace all intermediate results by generators, except where > a full noun is required. > > Worth considering in this context: > > $ > { > |. > %. > > > To translate the python statement to j, one would write (<./ 1 2 3 4 , 0 > 10 0 10), however we lose lots of time to python here due to calculating > the intermediate catenation (unless we are fortunate enough that the > interpreter has a Special Combination (SC) for this) > > How much is "a lot"? > > > For everyone who may be of the opinion that this is not worth it, I > would like to direct your attention to the existing jsources, where vast > amounts of effort for far smaller optimizations are apparent. > > As a general rule, J only accepts optimizations where there's a useful > problem where that optimization produces at least a factor of 2 > improvement. (Often enough it's more like factor of 1000.) > > > for example p.c, where the parser itself tries to emplace arrays and > avoid unnecessary copying. It is still unable to do this consistently > however, as simple memory tests like 7!:2 'i.1000x' ,: '>: i.1000x' prove. > (and yes I like using x for my benchmarks due to how much slower they are) > > I am not sure what you're talking about here - I took a quick look at > p.c but most of what I saw was implicit in the definitions. I'm not > comfortable calling that "optimizations". > > > another example is. jt.h, where a JFE's state information structure has > been lovingly crafted to optimize it's use of cpu cache > > or again the countless optimizations in the primitives, like n&i. hash > tables, the immensely flexible /: etc.. > > The hash tables aren't so good on large arrays, unfortunately - so > that's something that could maybe use some good insights. > > But the thing that worries me is how many things would break if you > tried to throw generators at them. That winds up being cases where > generators would slow things down (because you have the work of > building the generator and then interpreting the generator and you pay > in both code bloat and cache pressure and in cpu pipeline breakage and > of course any extra tests to keep things from breaking.) > > Put different: arrays are not "an optimization" in J. They are J's > fundamental data structure. > > Or, for a similar perspective: > > gnu gmp's bignum library looks like a nice-to-have > > the lapack library is a nice-to-have > > But integrating both of them would not solve the hard issues > associated with using them together. > > Also, thinking back to infinities: one useful tactic for implementing > math which involves infinities is to work in the reciprocal domain. > But - hypothetically speaking - there are potentially an infinite > number of different ways to work with infinities. > > Thanks, > > -- > Raul > ---------------------------------------------------------------------- > For information about J forums see http://www.jsoftware.com/forums.htm J Forums<http://www.jsoftware.com/forums.htm> www.jsoftware.com Forums. The J forum mailing lists give life to the J community. They are the best way to get help, help others, report bugs, and share your interest in J. ---------------------------------------------------------------------- For information about J forums see http://www.jsoftware.com/forums.htm J Forums<http://www.jsoftware.com/forums.htm> www.jsoftware.com Forums. The J forum mailing lists give life to the J community. They are the best way to get help, help others, report bugs, and share your interest in J. ---------------------------------------------------------------------- For information about J forums see http://www.jsoftware.com/forums.htm