3 ms·
There's no inherent reason why doing lazy evaluation in an eager-by-default language should be any harder than the reverse. I can imagine a language that is eag
by cvoss 4y ago
There's no inherent reason why doing lazy evaluation in an eager-by-default language should be any harder than the reverse. I can imagine a language that is eager by default but has a '#' operator that holds expressions in unevaluated form until terms are requested.
- ParetoOptimal 4y ago> There's no inherent reason why doing lazy evaluation in an eager-by-default language should be any harder than the reverse. lazy by default enables better composition and local reasoning. https://publish.obsidian.md/paretooptimaldev/Advantages+of+lazy+evaluation https://publish.obsidian.md/paretooptimaldev/Advantages+of+l...
- shirogane86x 4y agoSadly even though what you say is true, I do not know of any languages that get that right. Even those that do care enough to give you a way to make lazy values, they require you to explicitly wrap them and force them all over the place, making lazy programming effectively so noisy it's unusable. Which is the main reason why I still find myself coming back to haskell (stuff like parser combinators is just so unwieldy without laziness and do notation...)
- MauranKilom 4y agoCounterpoint: C++ expression templates have existed for a long time, and require no explicit work on the user side. They are incredibly unwieldy to write and debug though.
- shirogane86x 4y agoI am gonna be completely honest, I have never quite been able to understand expression templates properly. is it possible to use them to get hassle-free laziness? is there any example of a library that does this (just to look at it and see how it's done)?
- MauranKilom 4y agoDefine hassle-free. In readability of user code? Yes. In getting clean compiler errors? No. One example would be Eigen: https://eigen.tuxfamily.org/index.php?title=Main_Page https://eigen.tuxfamily.org/index.php?title=Main_Page See also their page on lazy evaluation: https://eigen.tuxfamily.org/dox/TopicLazyEvaluation.html https://eigen.tuxfamily.org/dox/TopicLazyEvaluation.html Of course, C++ is powerful enough that using specific tools can make the expression template abstraction fall apart (e.g. auto), but fundamentally you can write matrix code very cleanly and get great lazy-evaluated performance.
- Quekid5 4y agoWhile you're technically right, it's only in the same sense that any TC language can do anything any other TC language can -- you can theoretically always delay any computation behind a lambda, but the ergonomics have wide-ranging consequences. You also don't get any memoization that way -- without further runtime support. There was a good Reddit thread recently where a lot of experts weighed in: https://www.reddit.com/r/haskell/comments/wpbs4z/what_things_would_be_awkward_to_do_in_a/ikhtng3/ https://www.reddit.com/r/haskell/comments/wpbs4z/what_things... I recommend reading the thread -- lot's of great stuff in there, but... TL;DR: It's a lot more complicated than it seems at first and it's far from obvious that strict-by-default is worth the cost.
- chas 4y agoThe combination of lazy evaluation and state mutation/side effects can be pretty difficult to reason about. For example, if you have a function that changes a global variable as a part of a lazy computation, once that function could have been called you have no way of knowing if or when that global variable will change in the future. If you have other functions that depend on the value of that variable, their future behavior is now much more challenging to reason about than in a strict language. You can also imagine something akin to a race condition in which there are multiple lazy computations which could eventually set that variable to different values and the actual sequence of state transitions depends entirely on the dependency order of a possibly unrelated piece of code. In practice, this means that in languages that are strict by default, lazy computations are often forced to run in order to reason about the code, rather than because the actual results of the computation are required. Since pure functions compute the same results under lazy or strict evaluation and require that any data dependencies they have are explicitly provided as inputs, they interact with lazy computations in a much more tractable way. This means that adding a strictness operator to a lazy language is much easier than adding a laziness operator a a strict language. An alternate approach is what python did with generators where there is a data type for lazy computation, but it lives apart from the rest of the language, so it is mostly used for e.g. stream processing where a default-lazy approach is conceptually straightforward and is less likely to lead to extremely non-trivial control flow. This approach does, however, basically give up on having a laziness operator that will turn a strict computation into a lazy one.