4 ms·
You are going to have to be detailed and specific if you want that statement to be taken seriously. Ocaml is very obviously quite similar to haskell. What spe
by papsosouid 13y ago
You are going to have to be detailed and specific if you want that statement to be taken seriously. Ocaml is very obviously quite similar to haskell. What specifically is so much more work about compiling haskell? And why does only GHC suffer from this extra work while other compilers were able to compile haskell code in reasonable time and space?
- mightybyte 13y agoLaziness, purity, and graph reduction--i.e. it's a completely different execution model. Funny how you demand specifics here, but "faithfully replicate the mistakes of php/mysql worst practices as interpreted by rails" is left oh so vague.
- papsosouid 13y agoHow is laziness making ghc slow? Completely strict code doesn't compile any faster, and writing completely lazy ocaml code doesn't compile any slower. How would purity make compilation slower? I want specifics here because it is a specific, factual claim. My opinion on frameworks was left somewhat vague as it is simply my opinion and I had no reason to think anyone wanted more specifics on it. I'm happy to be more specific if you like, what did you want to know?
- mightybyte 13y agoSee chrisdone's comment above. For more details on how GHC began life, check out SPJ's book: http://research.microsoft.com/en-us/um/people/simonpj/papers/slpj-book-1987/ http://research.microsoft.com/en-us/um/people/simonpj/papers... You might also take a look at GRIN. Here's a quote from the GRIN paper: "For a lazy language like Haskell, compilers typically compile one module at a time. At first sight, this might appear as a good opportunity to optimize several procedures at once. However, it seems as if this does not apply very well to low level optimizations, like those presented in this paper, where the actual dynamic control flow is important... In a lazy language, a function that is local to a module in the source code might very well escape from the module at run time (if it is built into a closure) and then be called from somewhere else." I'm very interested in your thoughts on frameworks, but this isn't really the right forum. It's usually pretty easy to catch me in #snapframework on IRC.
- chrisdone 13y agoThe main problem is laziness and to some extent purity. And partly GHC is a bit of a pig. Pretty much everything starts out life as a thunk, and the compiler does its best to translate these into strict values which affects when things are evaluated and therefore the performance, whether things can be stored on the stack fully evaluated, as registers or boxed things on the heap that need forcing, etc. The good news is that purity makes it significantly easier to do inlining and reducings/transformations bordering on whole-program compilation. Code that looks like a load of function calls usually gets compiled down (if you use the -fext-core flag) to a couple case expressions. You have to do this to get reasonable, baseline, performance in Haskell. In OCaml—or ML, or any strict, mutating language—you get that for free, as a starting point. They mirror the architecture underneath so they're already fast from the get-go. It's not to do with type checking or anything like that. Type checking with GHC is very fast. If you use -fno-code, it can compile, e.g. a 9Kloc codebase of 65 modules in 1.361s on my machine. However, if you enable code generation, it takes 9.532s and that's with -O0: with -O2 it takes 32.910s. Fay, my unoptimized, non-optimizing Haskell→JS compiler will codegen that codebase in 1.940s. It would do it in less if I optimized the compiler's parser and codegen. But it's fast because I don't do anything. I don't do any flow analysis or strictness analysis or simplification or generation of core or compiling to C--. Fay's generated JS is not fast as a result. Compare that to if I were writing a Lisp compiler to JS, which would be easy because the source and the target are basically the same execution model.
- papsosouid 13y agoI understand optimizing haskell is a harder problem, but I don't mean producing optimized binaries, I only need to do that once in a while. I have to compile it thousands of times while developing, and turn off optimizations there since it is just a waste of time. But non-optimizing ghc is still incredibly slow. Wasn't yhc much faster than ghc back when it existed? Surely it must be possible to make ghc fast enough that development isn't seriously hindered?
- chrisdone 13y agoI dunno about Yhc. Jhc, at least, is slower than GHC. It depends on the settings and the project in my experience. If you're on a project like a Yesod app, then you have to conservatively rebuild a lot more than you would normally because TH doesn't lend itself well to incremental compilation and the compiling itself is slower too. Depending on the size of the project you're facing 5-15-30 seconds of waiting. That is actually monstrous and I hate it as much as you do, I cannot stand waiting for my app to rebuild, I turn to reddit, or YouTube. The more time waiting for feedback the less interactive and less enjoyable a programming experience is for me. So I think we're on the same page on that. On the other hand, if you're just using normal Haskell code with reasonably modularized file structure, GHC will be able to rebuild incrementally and link just that module quickly. E.g. if it's a web app, you can have MyProject.View.Person and just change something in a blaze-html template and hit F12 in your editor (as I do) and it'll rebuild and restart in a second. I mean, to rebuild hpaste entirely from scratch takes 5 seconds: $ time cabal build --ghc-options='-fforce-recomp -O0' Compiling [snip] Linking dist/build/hpaste/hpaste ... real 0m5.116s user 0m3.936s sys 0m0.680s Which is great. hpaste is only 4kloc, but your average codebase is between 3 and 15. In a normal development cycle you're changing just one or two modules at once, so with incremental compilation the refresh cycle is very fast. If you just want to type-check there is the -fno-code flag which brings it down to 1.2s to typecheck the whole project. Another approach I've taken with an IRC server (hulk) is running it inside GHCi. That works surprisingly well. Especially if you have your run function return the state as a mutable reference, then you can take a look at it while it's running and update it. Here's hpaste running in GHCi: λ> :set args "hpaste.conf" λ> tid <- forkIO main Listening on http://0.0.0.0:1234/ PASS ****** USER hpaste * * * NICK hpaste λ> :t tid tid :: ThreadId λ> killThread tid Shutting down... λ> tid <- forkIO main Listening on http://0.0.0.0:1234/ PASS ****** USER hpaste * * * NICK hpaste It's currently running on http://chrisdone.com:1234/ http://chrisdone.com:1234/ (I'll take it down later). Doesn't seem slow! Updating the code takes some milliseconds with :r and restarting is a case of killThread tid and fork again, some other milliseconds. So yeah, I feel you on dev time. I'm more inclined to the approaches that lead to more immediate development cycles, can't stand waiting. I'm Emacser/ex Common Lisper. GHC could be faster, but there are definitely circumstances which exacerbate its performance, I reckon, and ways to combat it (as above). I know that's not a very good answer, more of a workaround than a reason. I don't know why GHC is particularly slow if it's a lot slower than Yhc was. Other than all its separate build steps, I get the impression from what people say that it's just mounted up and become quite hairy. And memory usage has never been much of a concern for the compiler. That's a pity and I'm all for work being done on improving its performance.