6 ms·
>forced by its unfortunate choice of being lazy Being lazy is what makes the language so elegant. Even a high level game developer (Carmack?) said, at one poi
by alien_at_work 9y ago
>forced by its unfortunate choice of being lazy
Being lazy is what makes the language so elegant. Even a high level game developer (Carmack?) said, at one point, that his ideal language would be lazy by default.
- aninhumer 9y agoMy impression is that laziness forced people to invent new abstractions to deal with IO, because you can't rely on the easily predictable evaluation order of eager evaluation to provide a good enough solution. And it's those abstractions that make Haskell elegant. However now that we've invented them, while some things benefit from laziness, eager evaluation is probably a better default.
- alien_at_work 9y agoI would disagree with your impression. Laziness made lots of things very elegant but things like IO initially very hard. Eventually elegant solutions were found for IO as well. An example of the elegance is a simple function that takes some type which can be ordered and picking the "largest" one: max :: Ord a => [a] -> a max = head . sort (<) The type declaration says the function "max" takes a list of some type a, which is Orderable and will return one. The implementation says first sort the list, then return the first entry of the sorted list. In a strict language this would be a lot of wasted effort but in a lazy language (depending on how "sort" is implemented) what ends up happening is basically the same steps you would have to do to pick a max value. The unnecassary sorting of the rest of the list cannot happen because that result is thrown away before it can be accessed. If you asked someone to describe how to get the largest entry in a list, the most consice way to describe it would be to sort the list and then take the first entry. In Haskell the most concise way to describe something is often the correct implementation as well, and that's what I call elegance.
- jstimpfle 9y agoI consider it very inelegant to sort a list only for extracting the largest element. Usually sorting refers to a O(n log n) operation, which is a waste. Yes, for some sorting implementation taking the first element of the sorted list may actually amount to a linear time operation given that the sorting is carried out lazily, but that's not very obvious and may fail on you fast. Bad idea from an engineering standpoint. There is a better solution in Haskell, which is getMax $ mconcat (map Max [1,2,3,0::Int]) Or more abstractly findMin :: (Ord a, Bounded a) => [a] -> a findMin = getMax $ mconcat . map Max You need the ::Int so that it's bounded (by the smallest representable value, which Int does have, but Integer does not have). Now, if you actually try getting this version to work, you will notice there is a lot of conceptual overhead involved for such a small thing. And it bugs me that you have to use the "Bounds" machinery just because the type system doesn't know that the list is non-empty (which I assume here). So I ended up with it after fiddling with foldr1, mappend and so on, noticing that the underlying basics have changed AGAIN in Haskell... Really, I consider the following C thing to be so much clearer and better engineering: int getMin(int *a, int n) { int r = a[0]; for (int i = 0; i < n; i++) if (r > a[i]) r = a[i]; return r; } Apart from the fact that in practice there is usually enough context that you will never need such a function, because you get the minimum in constant time with some other clever trick...
- alien_at_work 9y ago>I consider it very inelegant to sort a list only for extracting the largest element. Which I explicitly stated would not be happening in my example. In reality, you couldn't just use "sort", you'd need to make sure it was a sort with the right behavior. But the point wasn't to show how to get the largest element in a list but rather to show how non-strict (i.e. "lazy") evaluation can make the simplest code actually correct. Obviously this doesn't apply in every possible case, but if you compare it to e.g. C which is pretty much never the case, it's a win in elegance IMO. >just because the type system doesn't know that the list is non-empty (which I assume here). In modern haskell there is a type where the list is statically known to be non-empty. > noticing that the underlying basics have changed AGAIN in Haskell... Not sure what you mean here, are you complaining about standard library changes? I personally hope Haskell keeps periodically breaking backwards compatibility until they fix more of the ugly parts of the standard. I'd hate to see it go the way of Java and be stuck with a hideous e.g. file access model because that's what the very first release had. >Really, I consider the following C thing to be so much clearer and better engineering: I find such a function not remotely clear and definitely not better engineered. * It's using a "for loop" so it could be a filter, fold, map or any combination of those. I can't know without reading it. * The function this proposes to replace was able to find the max of any type which can be ordered. This proposed replacement can only do ints. Given the radically reduced scope, the typing is sufficient but you won't have to add many features before the C compiler simply cannot help you anymore. Haskell's type system is much more powerful, stopping just short of the more advanced dependant type applications.