Hi, > I don't have any concrete measurements. The implementation is as fast > as I could make it, but it's still pretty slow -- for example, when > you compare it with a naive implementation.
Naive implementation --- do you mean non-composable promises (i.e. delays) or graph reductions (or STG or whatever)? > Most of the hit is due to > doing the right thing wrt exceptions: when there's an exception when a > promise is forced, the exception is stored as the "value" and will be > re-raised when forced again. For example, if you do this: > > (define a (delay (/ (random 2)))) > (force a) > > and get an error, you should get an error for future forces too. Yes. I believe this is right thing to do and I think (or want to think) that other languages, OCaml, Scala, F# or whatever, do the same. (I'll have to check myself...) But the penalty is incurred only when an exception is raised during the initialization; am I correct? I.e, if the initialization is successful, no cost is incurred due to this. You may well know it, but in Java, classes are initialized lazily and initialization failure is memorized so that later attempts to initialize the same class fail again. But, IIRC, they degenerate uncaught exceptions during initialization to an initialization-failure exception. I have not thought about the impact of this carefully, though. > > It's simple and works, which is nice; isn't it? > > It's very fragile, and when it breaks it's very hard to find out how > to fix it. Will you explain how/why it is fragile? It looks conceptually simple. You rewrite let rec x = y, y = M in E[x] into let rec x = M, y = x in E[x] The two graphs must be extensionally equivalent. Keiko _________________________________________________ For list-related administrative tasks: http://lists.racket-lang.org/listinfo/users