views:

1030

answers:

5

If you've bought into the functional programming paradigm, the chances are that you like both Erlang and Haskell. Both have purely functional cores and other goodness such as lightweight threads that make them a good fit for a multicore world. But there are some differences too.

Erlang is a commercially proven fault-tolerant language with a mature distribution model. It has a seemingly unique feature in its ability to upgrade its version at runtime via hot code loading. (Way cool!)

Haskell, on the otherhand, has the most sophisticated type system of any mainstream language. (Where I define 'mainstream' to be any language that has a published O'Reilly book so Haskell counts.) Its straightline single threaded performance looks superior to Erlang's and its lightweight threads look even lighter too.

I am trying to put together a development platform for the rest of my coding life and was wondering whether it was possible to mix Erlang and Haskell to achieve a best of breed platform. This question has two parts:

  1. I'd like to use Erlang as a kind of fault tolerant MPI to glue GHC runtime instances together. There would be one Erlang process per GHC runtime. If "the impossible happened" and the GHC runtime died, then the Erlang process would detect that somehow and die too. Erlang's hot code loading and distribution features would just continue to work. The GHC runtime could be configured to use just one core, or all cores on the local machine, or any combination in between. Once the Erlang library was written, the rest of the Erlang level code should be purely boilerplate and automatically generated on a per application basis. (Perhaps by a Haskell DSL for example.) How does one achieve at least some of these things?
  2. I'd like Erlang and Haskell to be able to share the same garabage collector. (This is a much further out idea than 1.) Languages that run on the JVM and the CLR achieve greater mass by sharing a runtime. I understand there are technical limitations to running Erlang (hot code loading) and Haskell (higher kinded polymorphism) on either the JVM or the CLR. But what about unbundling just the garbage collector? (Sort of the start of a runtime for functional languages.) Allocation would obviously still have to be really fast, so maybe that bit needs to be statically linked in. And there should be some mechansim to distinguish the mutable heap from the immutable heap (incuding lazy write once memory) as GHC needs this. Would it be feasible to modify both HIPE and GHC so that the garbage collectors could share a heap?

Please answer with any experiences (positive or negative), ideas or suggestions. In fact, any feedback (short of straight abuse!) is welcome.

Update

Thanks for all 4 replies to date - each taught me at least one useful thing that I did not know.

Regarding the rest of coding life thing - I included it slightly tongue in cheek to spark debate, but it is actually true. There is a project that I have in mind that I intend to work on until I die, and it needs a stable platform.

In the platform I have proposed above, I would only write Haskell, as the boilerplate Erlang would be automatically generated. So how long will Haskell last? Well Lisp is still with us and doesn't look like it is going away anytime soon. Haskell is BSD3 open source and has achieved critical mass. If programming itself is still around in 50 years time, I would expect Haskell, or some continuous evolution of Haskell, will still be here.

Update 2 in response to rvirding's post

Agreed - implementing a complete "Erskell/Haslang" universal virtual machine might not be absolutely impossible, but it would certainly be very difficult indeed. Sharing just the garbage collector level as something like a VM, while still difficult, sounds an order of magnitude less difficult to me though. At the garbage collection model, functional languages must have a lot in common - the unbiquity of immutable data (including thunks) and the requirement for very fast allocation. So the fact that commonality is bundled tightly with monolithic VMs seems kind of odd.

VMs do help achieve critical mass. Just look at how 'lite' functional languages like F# and Scala have taken off. Scala may not have the absolute fault tolerance of Erlang, but it offers an escape route for the very many folks who are tied to the JVM.

While having a single heap makes message passing very fast it introduces a number of other problems, mainly that doing GC becomes more difficult as it has to be interactive and globally non-interruptive so you can't use the same simpler algorithms as the per-process heap model.

Absolutely, that makes perfect sense to me. The very smart people on the GHC development team appear to be trying to solve part of the problem with a parallel "stop the world" GC.

http://research.microsoft.com/en-us/um/people/simonpj/papers/parallel-gc/par-gc-ismm08.pdf

(Obviously "stop the world" would not fly for general Erlang given its main use case.) But even in the use cases where "stop the world" is OK, their speedups do not appear to be universal. So I agree with you, it is unlikely that there is a universally best GC, which is the reason I specified in part 1. of my question that

The GHC runtime could be configured to use just one core, or all cores on the local machine, or any combination in between.

In that way, for a given use case, I could, after benchmarking, choose to go the Erlang way, and run one GHC runtime (with a singlethreaded GC) plus one Erlang process per core and let Erlang copy memory between cores for good locality.

Alternatively, on a dual processor machine with 4 cores per processor with good memory bandwidth on the processor, benchmarking might suggest that I run one GHC runtime (with a parallel GC) plus one Erlang process per processor.

In both cases, if Erlang and GHC could share a heap, the sharing would probably be bound to a single OS thread running on a single core somehow. (I am getting out of my depth here, which is why I asked the question.)

I also have another agenda - benchmarking functional languages independently of GC. Often I read of results of benchmarks of OCaml v GHC v Erlang v ... and wonder how much the results are confounded by the different GCs. What if choice of GC could be orthogonal to choice of functional language? How expensive is GC anyway? See this devil advocates blog post

http://john.freml.in/garbage-collection-harmful

by my Lisp friend John Fremlin, which he has, charmingly, given his post title "Automated garbage collection is rubbish". When John claims that GC is slow and hasn't really sped up that much, I would like to be able to counter with some numbers.

+3  A: 
  1. You could use an OTP gen_supervisor process to monitor Haskell instances that you spawn with open_port(). Depending on how the "port" exited, you would then be able to restart it or decide that it stopped on purpose and let the corresponding Erlang process die, too.

  2. Fugheddaboudit. Even these language-independent VMs you speak of have trouble with data passed between languages sometimes. You should just serialize data between the two somehow: database, XML-RPC, something like that.

By the way, the idea of a single platform for the rest of your life is probably impractical, too. Computing technology and fashion change too often to expect that you can keep using just one language forever. Your very question points this out: no one language does everything we might wish, even today.

Warren Young
Thanks for the reply, particularly the technical detail in 1. Your answer to 2. is what I expect most people will say - it's a further out goal than 1.Regarding the rest of coding life platform - I am 45 so it may be shorter than some on StackOverlow. But your point is well made. Fashions do change - but things like functional programming in general and message passing tend to be long lived ideas. So really I am looking for a platform that I can evolve.
Paul Delhanty
By my estimation, you have two fashion eras left before you're eligible to retire. :)
Warren Young
thanks for the estimate ;-)
Paul Delhanty
Regarding your answer to 2., I don't need to share data - *just* share the heap ;-)
Paul Delhanty
+1  A: 

The CLR supports tail call optimization with an explicit tail opcode (as used by F#), which the JVM doesn't (yet) have an equivalent, which limits the implementation of such a style of language. The use of separate AppDomains does allow the CLR to hot-swap code (see e.g. this blog post showing how it can be done).

With Simon Peyton Jones working just down the corridor from Don Syme and the F# team at Microsoft Research, it would be a great disappointment if we didn't eventually see an IronHaskell with some sort of official status. An IronErlang would be an interesting project -- the biggest piece of work would probably be porting the green-threading scheduler without getting as heavyweight as the Windows Workflow engine, or having to run a BEAM VM on top the CLR.

Steve Gilham
Thanks for the technical feedback on the CLR/JVM. IIRC correctly, there was an SPJ interview where he stated that the CLR had slightly more support for functional programming than the JVM, but I did not know why. Now I know the reason is the existence of the tail opcode.
Paul Delhanty
Regarding the link to AppDomains, that is certainly interesting, and might allow one to emulate some of the features of Erlang. However, it would be hard to achieve the proven level of reliability that Erlang has.
Paul Delhanty
Regarding IronHaskell, sure that might be technically possible one day. But, given the existence of F#, I don't see MSRC putting much effort into it. (SPJ stated in one interview that the existence of F# took the pressure off of him to make Haskell run on the CLR.) To me it looks like the reason that MSR funds Haskell development so as to have a very pure functional platform to develop ideas like software transactional memory, that might at a later date migrate to more mainstream languages.
Paul Delhanty
F# I guess, if it really takes off, could drive what the CLR needs. Say Don Syme decides to put type classes into F#, so the CLR gets higher-kinded polymorphism, which I have heard it needs for typeclasses, and then IronHaskell becomes possible ...
Paul Delhanty
+8  A: 

A lot of Haskell and Erlang people are interested in the model where Erlang supervises distribution, while Haskell runs the shared memory nodes in parallel doing all the number crunching/logic.

A start towards this is the haskell-erlang library: http://hackage.haskell.org/package/erlang

And we have similar efforts in Ruby land, via Hubris: http://github.com/mwotton/Hubris/tree/master

The question now is to find someone to actually push through the Erlang / Haskell interop to find out the tricky issues.

Don Stewart
Thanks! That appears to be the most informed answer so far. So it sounds like what I am asking for in 1. at least is pretty much what a lot of other people want already. That suggests it is a sensible direction, which is great to know. I knew about neither haskell-erlang nor Hubris ... off to check them out.
Paul Delhanty
haskell-erlang looks technically interesting, but it is GPL. I have nothing at all against the GPL - in fact I might use it myself for some future projects, so there is an element of hypocrisy here. But I would not use someone elses GPL code for something as foundational to my platform as an Erlang-Haskell bridge as it would very much restrict how I could license my codebase in the future.
Paul Delhanty
Hubris appears to be MIT licensed. That is closer, but probably could not be relicensed as BSD3. (Given the Mozilla triple relicensing episode from MIT to MIT/LGPL/GPL.) Really I would like my platform level Haskell code to be BSD3.
Paul Delhanty
BTW, thank you very much for writing the Real World Haskell book along with Bryan O'Sullivan and John Goerzen. It has been a great resource for me learning Haskell.
Paul Delhanty
Re: someone to actually push through Erlang / Haskell interop - I would be prepared to work on that, but I would need help and it would have to be BSD3 to fly for me.
Paul Delhanty
The haskell-erlang package isn't actually very big, so you could start by writing your own BSD licensed version, assuming that the author is unwilling to relicence when asked.
Ganesh Sittampalam
I don't like to ask people to relicense code. It seems kind of disrepectful - my asumption being that the author knew their own mind when they chose a license. Starting my onw BSD licensed version might be a possibility I guess. But there is always the risk of gettinmg sucked into a pointless BSD/GPL flamewar. So maybe I will wait a while to see whether there is more people than just me who'd like a BSD3 licensed Erlang / Haskell interop package.
Paul Delhanty
Note that you cannot relicense anything you don't own; only the owner can do that. However, you should be fine to do what you like with code under licenses like BSD3, and MIT is will restrict you no more than BSD3 will.
Curt Sampson
+2  A: 

You're going to have an interesting time mixing GC between Haskell and Erlang. Erlang uses a per-process heap and copies data between processes -- as Haskell doesn't even have a concept of processes, I'm not sure how you would map this "universal" GC between the two. Furthermore, for best performance, Erlang uses a variety of allocators, each with slightly tweaked behaviours that I'm sure would affect the GC sub-system.

As with all things in software, abstraction comes at a cost. In this case, I rather suspect you'd have to introduce so many layers to get both languages over their impedance mismatch that you'd wind up with a not very performant (or useful) common VM.

Bottom line -- embrace the difference! There are huge advantages to NOT running everything in the same process, particularly from a reliability standpoint. Also, I think it's a little naive to expect one language/VM to last you for the rest of your life (unless you plan on a.) living a short time or b.) becoming some sort of code monk that ONLY works on a single project). Software development is all about mental agility and being willing to use the best available tools to build fast, reliable code.

dizzyd
Thanks very much for your answer with the information about the Erlang per process heap. Well I guess I would share the heap from 1 Erlang process with 1 instance of the GHC runtime. Then for my quesion 1., I could pass immutable data between Erlang and Haskell without having to copy it.
Paul Delhanty
I seem to recall that Erlang didn't always copy immutable data between processes. Do you have any knowledge of that?
Paul Delhanty
I agree with you about the costs of abstraction. However, that often seems to be because most abstractions are not abstract enough - they in fact leak. I think it is a worthwhile quest to seek good abstractions - very difficult, but worh striving for none the less.
Paul Delhanty
Agreed, there are huge advantages to running in different processes. Very often it is the right choice, but not always. I would like to have the choice based upon empirical data. In fact, where I would must like to be able to share the Haskell (GHC) heap is at the bottom of the callstack to avoid the marshalling cost of FFI.
Paul Delhanty
By and large, messages are copied -- there are, of course, exceptions when dealing with large binaries. I believe that at the end of the day, however, it's less locking and cheaper overall to copy a message than to avoid the copy and do ref counting.
dizzyd
a) I plan on living as long as possible, but I am 45 so it is not something I take for granted anymore. it does mean that I am in a hurry. b) yes I do have a code monk project in the works that needs a stable platform. I might have to change language at somepoint, but I don't want to change design.
Paul Delhanty
Another reason I am interested in unbundling the garbage collector is the computer language shootout benchmarks. It would be nice to compare Erlang and Haskell side by side say using the same GC.
Paul Delhanty
Thanks for the reply on when messages are copied and when they shared. Noted for future reference.
Paul Delhanty
+3  A: 

As dizzyd mentioned in his comment not all data in messages is copied, large binaries exist outside of the process heaps and are not copied.

Using a different memory structure to avoid having separate per-process heaps is certainly possible and has been done in a number of earlier implementations. While having a single heap makes message passing very fast it introduces a number of other problems, mainly that doing GC becomes more difficult as it has to be interactive and globally non-interruptive so you can't use the same simpler algorithms as the per-process heap model.

As long as we use have immutable data-structures there is no problem with robustness and safety. Deciding on which memory and GC models to use is a big trade-off, and unfortunately there universally best model.

While Haskell and Erlang are both functional languages they are in many respects very different languages and have very different implementations. It would difficult to come up with an "Erskell" (or Haslang) machine which could handle both languages efficiently. I personally think it is much better to keep them separate and to make sure you have a really good interface between them.

rvirding
Thanks for the reply. I might not have expressed it very clearly, but I agree with most of what you have written, particularly the bit about there being no universally best model for GC. It will get a bit long and rambling if I respond further in this comment, so I am going to add an "Update 2" to my question.
Paul Delhanty