An old article I occasionally see cited today is Repeat after me: “Cabal is not a Package Manager”. Many of the complaints don’t apply to cabal-install 1.24’s new Nix-style local builds. Let’s set the record straight.
Fact: cabal new-build doesn’t handle non-Haskell dependencies
OK, so this is one thing that hasn’t changed since Ivan’s article. Unlike Stack, cabal new-build will not handle downloading and installing GHC for you, and like Stack, it won’t download and install system libraries or compiler toolchains: you have to do that yourself. This is definitely a case where you should lean on your system package manager to bootstrap a working installation of Cabal and GHC.
Read more...
When you run make to build software, you expect a build on software that has been previously built to take less time than software we are building from scratch. The reason for this is incremental compilation: by caching the intermediate results of ahead-of-time compilation, the only parts of a program that must be recompiled are those that depend on the changed portions of the dependency graph.
The term incremental compilation doesn’t say much about how the dependency graph is set up, which can lead to some confusion about the performance characteristics of “incremental compilers.” For example, the Wikipedia article on incremental compilation claims that incremental compilers cannot easily optimize the code that it compiles. This is wrong: it depends entirely on how your dependency graph is set up.
Read more...
Why are macros in Haskell terrible, but macros in Racket great? There are certainly many small problems with GHC’s Template Haskell support, but I would say that there is one fundamental design point which Racket got right and Haskell got wrong: Template Haskell does not sufficiently distinguish between compile-time and run-time phases. Confusion between these two phases leads to strange claims like “Template Haskell doesn’t work for cross-compilation” and stranger features like -fexternal-interpreter (whereby the cross-compilation problem is “solved” by shipping the macro code to the target platform to be executed).
Read more...
I recently solved a bug where GHC was being insufficiently lazy (yes, more laziness needed!) I thought this might serve as a good blog post for how I solve these sorts of laziness bugs, and might engender a useful conversation about how we can make debugging these sorts of problems easier for people.
Hark! A bug!
Our story begins with an inflight patch for some related changes I’d been working on. The contents of the patch are not really important—it just fixed a bug where ghc --make did not have the same behavior as ghc -c in programs with hs-boot files.
Read more...
cabal new-build, also known as “Nix-style local builds”, is a new command inspired by Nix that comes with cabal-install 1.24. Nix-style local builds combine the best of non-sandboxed and sandboxed Cabal:
- Like sandboxed Cabal today, we build sets of independent local packages deterministically and independent of any global state. new-build will never tell you that it can’t build your package because it would result in a “dangerous reinstall.” Given a particular state of the Hackage index, your build is completely reproducible. For example, you no longer need to compile packages with profiling ahead of time; just request profiling and new-build will rebuild all its dependencies with profiling automatically.
- Like non-sandboxed Cabal today, builds of external packages are cached globally, so that a package can be built once, and then reused anywhere else it is also used. No need to continually rebuild dependencies whenever you make a new sandbox: dependencies which can be shared, are shared.
Nix-style local builds work with all versions of GHC supported by cabal-install 1.24, which currently is GHC 7.0 and later. Additionally, cabal-install is on a different release cycle than GHC, so we plan to be pushing bugfixes and updates on a faster basis than GHC’s yearly release cycle.
Read more...
Content advisory: This is a half-baked research post.
Abstract. Top-level unpacking of existentials are easy to integrate into Hindley-Milner type inference. Haskell should support them. It’s possible this idea can work for internal bindings of existentials as well (ala F-ing modules) but I have not worked out how to do it.
Update. And UHC did it first!
Update 2. And rank-2 type inference is decidable (and rank-1 existentials are an even weaker system), although the algorithm for rank-2 inference requires semiunification.
Read more...
ghc --make is a useful mode in GHC which automatically determines what modules need to be compiled and compiles them for you. Not only is it a convenient way of building Haskell projects, its single-threaded performance is good too, by reusing the work of reading and deserializing external interface files. However, the are a number of downsides to ghc --make:
- Projects with large module graphs have a hefty latency before recompilation begins. This is because
ghc --make (re)computes the full module graph, parsing each source file’s header, before actually doing any work. If you have a preprocessor, it’s even worse. - It’s a monolithic build system, which makes it hard to integrate with other build systems if you need something more fancy than what GHC knows how to do. (For example, GHC’s painstakingly crafted build system knows how to build in parallel across package boundaries, which Cabal has no idea how to do.)
- It doesn’t give you any insight into the performance of your build, e.g. what modules take a long time to build or what the big “blocker” modules are.
ghc-shake is a reimplementation of ghc --make using the Shake build system. It is a drop-in replacement for ghc. ghc-shake sports the following features:
Read more...