Linux Kernel Modules in Haskell (2009)
tommd.wordpress.com
tommd.wordpress.com
One approach that I find much more promising is using Haskell (or other robust and semantically easy to reason about and easy to verify languages) to generate C code which then can be used with normal toolchains for low-level development. Galois is doing a lot of work in this area that looks very promising. One of their projects is an autopilot system called SMACCMPilot[0] that uses a Haskell eDSL called Ivory[1] to generate safe C code. I am particularly excited about its integration with FreeRTOS tasks using the Tower Language[2] (another Haskell eDSL).
This makes it possible to generate code that can be reasoned about with Haskell but has the runtime characteristics of C. This is particularly interesting because embedded systems code is notoriously non-composable and difficult to reason about due to the enormous shared state of the hardware itself and the highly concurrent nature of interrupt-driven design. Embedded C makes a good target for this sort of design and analysis though, because it has very constrained memory usage (developers typically eschew dynamic allocation), very subtle potential issues (debugging race conditions with LEDs sucks), and very serious consequences for errors[3].
[0]http://smaccmpilot.org/index.html
[1]http://smaccmpilot.org/languages/ivory-introduction.html
This is FUD, repeated ad nauseum all over the internet as a misinterpretation of what Simon Peyton Jones said once during a talk. In case you hadn't noticed, there appears to be a tradition in programmer circles of picking SPJ quotes and turning them into memes. "Haskell is useless!" and "Avoid success at all costs!" are some others.
The reality is far less extreme than most people think. It is not at all unreasonable to write low-level code such as device drivers in Haskell. This has actually been done as part of the HaLVM project.
I think you have this backwards. People have been saying that laziness has unpredictable performance characteristics (especially when it comes to space usage) as long as there have been lazy functional languages. SPJ was referring to that common sentiment; it didn't somehow materialize because of comment he made during a talk.
There was an era where space complexity and space usage semantics were a big deal in functional programming, e.g. the work on giving a precise definition of "tail call optimization" and the emphasis on space safety that has since been present in the strict functional programming world. In contrast, there is no standard space semantics for lazy languages, and certainly none that GHC respects. It's tricky when simple CSE can dramatically alter the space complexity of your program, e.g.
https://ghc.haskell.org/trac/ghc/ticket/947 https://ghc.haskell.org/trac/ghc/ticket/1752
The problem with FUD is that it takes reasonable statements and exaggerates them to an unreasonable degree. People repeat the word "difficult", eventually someone starts using "very difficult", sooner or later people start throwing around "impossible".
It's not surprising that people manage to produce lots of working programs despite this, though. Almost all life-critical software is written in completely unsafe languages.
This is not exclusive to Haskell; even C compilers will do this with jump tables and so on.
http://queue.acm.org/detail.cfm?id=2538488
http://neilmitchell.blogspot.com/2013/02/chasing-space-leak-...
He appears to use profiling tools and "try them all and see which produces the most useful information", to me that sounds very different from reasoning.
http://blog.ezyang.com/2011/05/anatomy-of-a-thunk-leak/
and particularly this:
http://blog.ezyang.com/2011/05/an-insufficiently-lazy-map/
One point I'd like to mention: just because it seems complex and intimidating for beginners/outsiders does not mean it is intractable for experienced programmers.
This is a relatively old presentation of theirs, but it has a decent overview of what they have used Haskell for. http://www.cse.chalmers.se/edu/year/2010/course/TDA555/Mater...
[1]: https://speakerdeck.com/mchakravarty/embedded-languages-for-...
Native Oberon, Spin, Singularity, ...
Simply put, how much more capable is this? Certainly more concise and has some aesthetic appeal. Just curious if it brings a lot more to the table.
I don't think the C tooling is that great. Haskell has some neat tooling of its own.
So, this really doesn't answer my question. I can't but agree that the tooling in Haskell is above that of plain C. However, what class of bugs will be prevented in the kernel, that isn't already fairly well handled with existing tooling. Consider that the kernel is actually fairly solid code, if I'm not off my rocker.
There's one cost you've ignored: feedback time. A type-checker can be run on the fly with tools such as flymake. Debugging tools and tests are (orders of magnitude) slower to run and thus dramatically slow down the feedback cycle between bug detection and bug fix. This is especially prevalent when doing major refactoring work and the code is a long way from working again.
For intstance, languages with weak static typing seem to lead to "stringly typed" solutions.
The C specification is pretty clear on what it has purposefully left undefined which has made it rather resilient to changes in underlying hardware architectures.
Must be why Haskell's run-time support is written in C [2]
[1] http://thoughtmesh.net/publish/367.php [2] https://github.com/ghc/ghc/tree/master/rts
However, not every kernel driver and not every application needs the benefit of C or undefined behavior.
The fact that Haskell's RTS is written in C is evidence that the kind of code in RTS's has more to gain from C than from Haskell. Some parts of drivers might also be best written in C.
Right tool for the job after all. For many use cases in my experience though, you don't want undefined behavior.
You can encode an arbitrary amount of information into a verified, proven specification.
The specification is orders of magnitude smaller and simpler than the actual code, so much easier to get correct.
"Proven," in as far as you trust the axioms and assumptions made by the Haskell compiler. It's an important distinction because you must assume that the 50k lines of C code that get compiled and statically linked into your Haskell programs is also, "correct," by extension despite it living outside the set of axioms and assumptions your program has been proven within.
Don't get me wrong, Haskell is a neat language, I just don't accept its trade-offs for most of the work I do.
Thus far I've been able to accomplish things rather easily, but I don't believe I've written enough to form a solid opinion yet.
As far as the Haskell compiler living outside of that set of axioms and assumptions my program has been proven with, that is something that does needle me a little but it seems to be a smaller hole than most languages are working with.
But you'll prevent orders of magnitude more bugs that would waste your time debugging in the best case, or hit production in a slightly worse case.
This reminds me a lot of xmonad. I guess higher level languages are migrating downwards to the system level slowly.
Sure, I (as a heavy Haskell user) would rather catch such things at compile time, but given the choice between catching them at runtime and not catching them at all, I'd almost never choose the latter unless there are other overriding concerns.
My own kernel (https://github.com/fotcorn/kernel) is hacked together with code from osdev.org.
http://www.amazon.com/Operating-Systems-Design-Implementatio...