4 ms·
Their code is import qualified Data.Vector as U main = print . U.sum $ U.enumFromTo 1 (100000000 :: Int) Possibly it's just because I don't grok Hask
by colomon 17y ago
Their code is
import qualified Data.Vector as U
main = print . U.sum $ U.enumFromTo 1 (100000000 :: Int)
Possibly it's just because I don't grok Haskell, but that strikes me as incredibly ugly for such a simple operation. As a contrast, here's the Perl 6 version:
say [+] 1..100000000
(For sure there is no Perl 6 implementation that will run the code as fast as they show GHC running it -- odds are, in fact, that the current Perl 6 implementations will be drastically slower.)
I suspect there is a more elegant version in Haskell, too -- it probably just doesn't run nearly as fast. This has been one of my main gripes with my experiments with functional languages. It seems they are always showing you this beautiful elegant code, and then explaining how if you want it to be efficient, you need to use a different, much uglier, approach.
Of course, the other thing with this is the example is completely unrealistic. If you actually wanted to compute that number, the fast way to do it is to use the good old formula
(N * (N-1))/2
If for some reason you wanted to compute that sort of thing a lot, to would make a lot more sense to make a simple function to calculate that...
- dons 17y agoI'm sorry I used a trivial example -- the point was to show how the assembly corresponded to the fused loop, which necessitated a simple example. And this is the internet, so everyone tries to find a closed form for everything. Which misses the point! Of course, the Haskell: print (sum (enumFromTo 1 n)) isn't exactly bad. And you can use any of these other 134 functions to get fused loops: http://hackage.haskell.org/packages/archive/vector/0.5/doc/html/Data-Vector.html#1 http://hackage.haskell.org/packages/archive/vector/0.5/doc/h... And there's lots of interesting problems you can solve with that rich a set of primitives. This isn't an example benchmark, it's an example translation, so you can see the optimization at work. Bigger examples yield assembly that no casual reader could follow -- so don't get distracted by the fact there's a closed form!!
- colomon 17y agoGlad to see there is a prettier way of doing it in Haskell! Do I understand then that this basically building up a sort of parallel language for expressions in Haskell which optimize really, really well?
- dons 17y agoIn a way. It's a subset of Haskell focused on array operations that optimize really really well. You can use these instead of list operations, basically, and getter performance in all sorts of ways.
- eru 17y agoYou could get very good performance when you do the fusion manually, too. The really exciting thing about fusion is that it allows really fast code that _composes_ well. Composability is also what makes Haskellers excited about Monads and software transactional memory (STM). STM give composable concurrency --- in contrast with locks which are notoriously uncomposable.
- gwern 17y ago> Glad to see there is a prettier way of doing it in Haskell! Most Haskellers would write it a little differently from Don: 'main = print $ sum [1..n]'. The '..' is syntactic sugar over 'enumFromTo'.
- eru 17y agoI'd prefer main = print . sum $ [1..n] But that's almost the same.
- dons 17y agoYes, you can of course use lists. I'm interested in getting the compiler to produce the best code it can, hence I use slightly different libs and flags and such.
- eru 17y agoYour version is good. I just wanted to give a small sample of idiomatic Haskell code. Colomon's post (and his subsequent enlightened reply) were good parts of the discussion, too.