To get some idea what's going on here: In Haskell, all functions are pure and arguments are lazily evaluated.
There are two ways to do lazy evaluation: (a) substitution: replace the parameter by the argument in a cloned function body and evaluated that. Cloning the body can generate a new function we call, or we could inline it for even further performance gain. Substitution is the fastest method provided the argument isn't used many times. (b) Wrap the argument in a closure and evaluate that when required. This is sometimes sped up by caching the result. This is generally SLOW. In order to improve performance, Haskell defines the concept of strictness. If a function isn't total, it can bug out. If a function takes an argument which bugs out, and the function also necessarily bugs out too, the function is said to be strict (in that argument). This is written f (bug) = bug where bug is called bottom and isn't a real value. The reason strictness is important is this: if a function is strict in an argument, then if the argument is going to bug out, it doesn't matter whether it bugs out by being evaluated before calling the function or after. So if a function is strict, we can use eager evaluation without changing the semantics. Eager evaluation is useful in two cases where lazy evaluation is slow: (a) substitution: many uses of the argument cause multiple evaluations. (b) closures, when the argument can just be passed in a variable (instead of itself being a closure to ensure it isn't evaluated too early). So we have: if a function is pure and strict then indeterminate evaluation has no semantic impact and is clearly optimal because the compiler can choose. So these then are sufficient conditions for a "val" in Felix too. The initialiser has to be composed of pure strict functions. In that case it doesn't matter when the evaluation is done. however, these conditions are too .. ah .. strict. Its fine to refer to a variable if the value is the same with either evaluation strategy. In particular, if the variable has its final value before the earliest possible evaluation of the val, or, at least doesn't change until after the last possible use. So as long as the variable is invariant in the potential evaluation range, that's enough. I could make some words here such as: if the variable changes that extinguishes the val that depends on it. Felix current checks for extinguishment (but not initialisation!) When it sees a sequence of vals, val x = .. val y = .. val z = ... is substitutes x into y and z, and y into z in an attempt to eliminate x and y. Variables waste space in objects. [Recall Felix functions and procedures are notionally C++ objects] It checks how many uses there are too: if there are more than 2 it doesn't substitute, it keeps the variable (eager evaluation). When it sees a label, a goto, and perhaps a variable assignment or procedure call it stops substituting. If it substituted all occurrences of the variable a subsequent garbage collection pass will eliminate the variable -- unless its a parameter which is really tricky! However there's no strictness check. one might be added, at the cost of having to annotate all C function bindings, to tell if they're strict. Then perhaps Felix might be able to tell if a function derived from these is strict. However, the result wouldn't be optimal because Felix would have to be conservative. At present, Felix is optimal because instead it is aggressive (it acts as if functions are strict). Note you can always ensure lazy evaluation (at the moment anyhow) by explicitly passing a closure. There are some other tricks too: mark the function noinline to ensure the function is a closure and you'll get eager evaluation of the arguments With a couple of caveats such as if the parameter isn't used and the function is called directly. This bites if the argument is a generator: such generator calls can then be elided, losing their side effects. be warned of that, it applies to variables too: var x = g 1; will do nothing, no matter what g does, because x isn't used. Fix it by: C_hack::ignore (g 1); Note: this is desirable! You can safely make a pool of worker threads and if you don't use it, it doesn't exist. Anyhow just as an example the C function: c ? t : f is strict in c, but not t or f. Similarly a && b is strict in a but not b. OTOH a,b is strict in both. -- john skaller skal...@users.sourceforge.net http://felix-lang.org ------------------------------------------------------------------------------ LogMeIn Rescue: Anywhere, Anytime Remote support for IT. Free Trial Remotely access PCs and mobile devices and provide instant support Improve your efficiency, and focus on delivering more value-add services Discover what IT Professionals Know. Rescue delivers http://p.sf.net/sfu/logmein_12329d2d _______________________________________________ Felix-language mailing list Felix-language@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/felix-language