terminal-auspicious

Topics

programming

php drupal scheme scheming macros design patterns da la

design

design css

random thoughts

scribbles

alter ego

other me 'em that link us my space me linked in

Collections

Programmable web
PHP design patterns

Similar things

  • Learning to speak - erlang style concurrency in haskell
  • Relations and their domain structures
  • Learning lessons from Lisp or patterns and languages in PHP
  • Emulating closures in PHP
  • Some ways to use saved state with closures in php
  • Scoped php functions or more ways to abuse php
  • Overcomplicated design pattern implementations
  • Ok, Ok, the code will follow (very) soon
  • Relation modules
  • Relations battle plan

Home » blogs » vlado's blog

Learning to speak - erlang style concurrency in haskell ( part II )

Submitted by vlado on Fri, 2007-11-23 00:19.code | erlang | haskell | scribbles

A second installment of my attempt to code erlang-style concurrency abstraction in haskell. The effort in part I, was a bit short of the mark. Here I try to address some of the shortcomings, while leaving others open.

The main problem was that the receiver could escape outside of the process, which can cause various hard to debug mayhem. What will happen if two different threads receive data from the same channel? Yes, it might be intentional, but you could always duplicate a channel for that. What if it is a bug? What if it is a piece of malicious code? Better safe than sorry.

The idea is to use the type system to ensure at compile time that there are no leaks. I chose to use implicit parameters, rather than existential types. It looked simpler and I think it produces similar code. In the code below the receivers and unGet are put into the dynamic scope of proc - the 'process' function. This ensures that they are available for use inside runProcess, but inaccessible otherwise. Trying to use them outside of the scope of runProcess should give a type error. The downside is that every process body function must be annotated appropriately. Well, I think it is worth the effort.


data Process a = Process  (a -> IO (Maybe ()))      -- write message
                          (IO Bool)                 -- is open?
                          (IO (Maybe Bool))         -- is empty?

runProcess :: Process (Process a) -> (Process a -> IO ()) -> IO ()
runProcess (Process sendBack isOpen isEmpty) proc = do
    mbox <- newMBox
    let ?receive = readMBox mbox
    let ?tryReceive = tryReadMBox mbox
    let ?unGet = unGetMBox mbox
    let p = (Process (writeMBox mbox) (isOpenMBox mbox) (isEmptyMBox mbox))
    ok <- sendBack p
    case ok of
        Just _ -> bracket 
                    (return p) 
                    (\_ -> (closeMBox mbox)) 
                    proc
        Nothing -> (closeMBox mbox)

The various mbox functions and the MBox object are simple wrappers around Chan in order to make it behave more like a file handle. Thus isOpen, and the nested Maybe types in the return types. The outer signals the opennes - Nothing means "nope mate, no luck, this one is gone, try something else, and better loose it". This nicely leads to another problem. This model of processes has a potential for resource leaks. Ideally all channels will be garbage collected. Unfortunately, nothing guarantees that the write/open?/empty? mbox functions are not alive (referred to) by a live code. Channels are very similar to pointers in this respect. Just a touch safer.

It is interesting how these leaks can be avoided. I don't like the erlang solution very much - to use addressing of one form or another, and kill the process on error. The latter part is fine. It is trivial to implement, but I'm not convinced yet. Another way is to have some form of cooperation, plus in closeMVar, to finalise channel and leave a minimal callback. Alas, another time

AttachmentSize
Process.hs_.txt1.54 KB
MBox.hs_.txt2.79 KB
vlado's blog | add new comment
Home » blogs » vlado's blog

dikini.net

spreading confusion by accident since 1970