views:

279

answers:

3

I would like to how can we implement producer/consumer in a functional programming language like Haskell? and how it will be different from an Imperative language? My understanding of functional programming language is primitive. Any help will be appreciated.

+10  A: 

A producer/consumer abstraction using preemptive threads and messages passed through a channel:

import Data.Char
import Control.Concurrent
import Control.Concurrent.Chan

main = do
    c  <- newChan
    cs <- getChanContents c     -- a lazy stream of events from eventReader
    forkIO (producer c)          -- char producer
    consumer cs

  where
    -- thread one: the event producer
    producer c = forever $ do
        key <- getChar
        writeChan c key

    -- thread two: the lazy consumer
    consumer = mapM_ print . map shift
        where shift c | isAlpha c = chr (ord c + 1)
                           | otherwise = c

You would use a similar model in Erlang. Threads to represent the consumer and producer, and a shared pipe of messages between them, each acting asynchronously.

Don Stewart
This answer describes how one might solve this problem imperatively. Or more precisely, how to functionally generate an imperative computation that solves the problem. I wonder if Shiva was looking for a purely functional solution.
Conal
+4  A: 

I will add to dons's excellent answer that the underlying mechanism here is something called an MVar, and it is an imperative, parallel container for a value. You "put" and "get" into and out of an MVar. Getting an empty MVar blocks, as does putting a full one. It's simultaneously a communication mechanism and a synchronization mechanism. I believe it was invented by Arvind as part of the Monsoon/*t project. There is a beautiful book by Nikhil and Arvind which explains their pH dialect of parallel Haskell. Many of the ideas have been adopted into GHC, and the book is well worth reading.

Norman Ramsey
+1  A: 

Besides the stateful approaches mentioned by Norman and Don, you can also think of normal function application and laziness as producer and consumer.

Here is a producer for the natural numbers:

nats = [1..]

And here is a consumer that computes the squares of those numbers:

squares = map (\x -> x * x) nats

Producers such as yield return in C# or generators in Python can often be expressed like this: as simple lazy lists in Haskell.

Martijn
however in Python generators can have side effects (unlike pure lists). you can achieve that too with monadic lists, and you can also generate those with "yield" like in Python with the GeneratorT monad transformer from the generator package.
yairchu