ideas-computer-jasper-jasperLazy

safe autostrictification, eager, lazy, lazyrec:

1) you can declare functions as 'lazyrec', meaning that you don't want autostrictification within them 2) when calling functions, you can call them thru the functor 'lazyrec', which is like declaring them 'lazyrec' just for that call 3) you can declare values as 'lazy', meaning that you don't want autostrictification applied to them or their heirs 4) you can declare values as 'eager', meaning that you want strictification applied to them and their heirs

during compile time:

1) infer substructural recursion. Mark such functions as 'only yields infinite data if given infinite data'. (this covers 'sum') 2) infer functions will only recur on some of their arguments, and mark them as 'always yields finite data' and 'only yields infinite data if given infinite data' in the other arguments (this covers 'take') 3) transitively dataflow trace eager data through functions that 'only yields infinite data if given infinite data', to mark their outputs as eager when only eager data is provided 4) transitively dataflow trace lazy data through functions that are not 'always yields finite data', to mark their outputs as lazy when lazy data is provided 5) the transitive dataflow traces of eager and lazy end when you get above the lexical scope of the original eager/lazy declaration. for these purposes a declaration inside the arguments passed to a function are their own lexical scope. e.g. in 'y = f (eager x) w', y is not eager. 6) if any value is marked both 'eager' and 'lazy' then raise a compile-time error

and then during runtime:

1) upon exiting a function or calling into a function, for those outputs or parameter values that are marked eager, strictify 2) upon exiting a function, check to see if we are stuck in a mutual recursion loop that has not produced any lazy output in an entire pass. If so, then unless either (a) the data is marked 'lazy', or (b) the function at the top of the loop is marked 'lazyrec', strictify.

--

mb we need to allow the programmer to mark sections of code (like the atomic marker and the transaction marker) to which stream fusions should be applied?

or can the compiler discover this automatically?

--

it seems that the key thing w/r/t foldl, foldr, and stack overflows, is for the compiler to recognize a function or functions which recursively call into themselves (possibly without strictification) in a way that may cause a stack overflow if they are fed an input list longer than a certain length. in this case, either (a) the compiler can add strictification or convert almost-tail-recursive code to tail recursive, (b) the user has marked this operation as "dangerous", or (c) there is a compile-time error.

but forcing the user to explicitly mark this as 'dangerous' seems inconsistent with my decision that side-effectful functions need not be marked as such (although pure functions can be marked as such). why should this be any different? related, i am forcing the programmer to explicitly mark references in data structures.

--

perhaps, if an opportunity for stream fusion is detected, this can just overrule the detection of a strictification opportunity? or can there exist situations where stream fusion would be possible but this coexists with a foldl-ish danger that would be nullified by a conversion to foldl'?

--

data could have a dynamic __shouldStrictify function, dynamizing the 'strict data flag' idea

--

so i guess there are 3 possible types of assurances on function termination:

(1) if all of the inputs are finite, then the output is finite (this sort of assurance is provided by structural recursion proofs) (2) if all of the inputs are finite, then the output may be infinite, but a request for just the head will terminate (this sort of assurance is provided by guarded recursion proofs) (3) (no assurance on termination) if all of the inputs are finite, then the output may be infinite, and even a request for just the head may not terminate

---

unify laziness and promises

---