Peter,
Roughly, I'd say you can fudge laziness in data structures
in a strict language without too much bother. (I don't have much
experience with this, but the existence of a streams library for OCaml
is the sort of thing I mean. There are plenty of papers on co-iterative
streams and suchlike that show the general pattern.)
Yes, agree. And this was my initial point.
If you wish to add control structures you would need to use the lazy
keyword a lot, e.g.:
if cond then *lazy* S1 else *lazy* S2
and for more complicated structures it's not going to be always clear
what needs to be suspended. Laziness is a conservative default here.
(If you want to write an EDSL in a non-lazy language, you'll need to
use some kind of preprocessor / macros / ... - in other words, a
two-level language - or do thunking by hand, as above, or live with
doing too much evaluation.)
One way to gauge how useful laziness really is might be to look through
big ML projects and see how often they introduce thunks manually. A
thunk there is usually something like "fn () => ..." IIRC. Also
IIRC, Concurrent ML is full of them.
Probably, dealing with macros is not so scary and Paul Graham and Piter
Siebel show that it is quite easy. :-)
Ok, let's go from the another side:
I have searched through Darcs source and found 17 datastructures with
strict members (for example data Patch = NamedP !PatchInfo ![PatchInfo]
!Patch) and 36 occurrence of this dreaded seq. And Darcs is an
application being not speed critical.
And if one try to write cipher decoder on Haskell, I guess he has to
make his program full of '!' and 'seq' (or FFI).
Dare I say the tradeoff is between a relatively simple
operational model (so you can judge space and time usage easily) and
semantic simplicity (e.g. the beta rule is unrestricted, easing program
transformation).
Cool! Thank you.
Best regards,
Nick.