Alen Ribic / @alenribic
January 2013, Lambda Luminaries
Cloud Haskell is a DSL for developing programs for a distributed computing environment in Haskell.
Often called the 'Actor model'
newtype Process a = Process {
unProcess :: ReaderT LocalProcess IO a
} deriving (Functor, Monad, MonadIO, MonadReader LocalProcess,
Typeable, Applicative)
data ProcessId
data NodeId
class (Binary a, Typeable a) => Serializable a
send :: Serializable a => ProcessId -> a -> Process ()
expect :: Serializable a => Process a
receiveWait :: [Match b] -> Process b
receiveTimeout :: Int -> [Match b] -> Process (Maybe b)
match :: Serializable a => (a -> Process b) -> Match b
matchIf :: Serializable a => (a -> Bool) -> (a -> Process b) -> Match b
spawn :: NodeId -> Closure (Process ()) -> Process ProcessId
terminate :: Process a
getSelfPid :: Process ProcessId
getSelfNode :: Process NodeId
link :: ProcessId -> Process ()
monitor :: ProcessId -> Process MonitorRef
say :: String -> Process ()
+------------------------------------------------------------+
| Application |
+------------------------------------------------------------+
| |
V V
+-------------------------+ +------------------------------+
| Cloud Haskell |<--| Cloud Haskell Backend |
+-------------------------+ +------------------------------+
| ______/ |
V V V
+-------------------------+ +------------------------------+
| Transport Interface |<--| Transport Implementation |
+-------------------------+ +------------------------------+
|
V
+------------------------------+
| Haskell/C Transport Library |
+------------------------------+
Implementations
Also possible
"SimpleLocalnet" backend
"Windows Azure" backend
Building a distributed app to find and sum up a number of prime factors for every natural number [1..n]
factors :: [Integer] -> Integer -> [Integer]
factors qs@(p:ps) n
| n <= 1 = []
| m == 0 = p : factors qs d
| otherwise = factors ps n
where
(d,m) = n `divMod` p
primeFactors :: Integer -> [Integer]
primeFactors = factors primes
numPrimeFactors :: Integer -> Integer
numPrimeFactors = fromIntegral . length . primeFactors
Written by Dan Weston
Push work to available nodes and sum up the results
master :: Integer -> [NodeId] -> Process Integer
master n slaves = do
us <- getSelfPid
-- Start slave processes
slaveProcesses <- forM slaves $
\nid -> spawn nid ($(mkClosure 'slave) us)
-- Distribute 1 .. n amongst the slave processes
spawnLocal $ forM_ (zip [1 .. n] (cycle slaveProcesses)) $
\(m, them) -> send them m
-- Wait for the result
sumIntegers (fromIntegral n)
sumIntegers :: Int -> Process Integer
sumIntegers = go 0
where
go :: Integer -> Int -> Process Integer
go !acc 0 = return acc
go !acc n = do
m <- expect
go (acc + m) (n - 1)
Compute the number of prime factors and send results to master node
slave :: ProcessId -> Process ()
slave them = forever $ do
n <- expect
send them (numPrimeFactors n)
remotable ['slave]
main = do
args <- getArgs
case args of
["master", host, port, n] -> do
backend <- initializeBackend host port rtable
startMaster backend $ \slaves -> do
result <- master (read n) slaves
liftIO $ print result
["slave", host, port] -> do
backend <- initializeBackend host port rtable
startSlave backend
./prime-factors slave localhost 8081
./prime-factors master localhost 8080 100
=> 239
For more examples, check out the distributed-process-demos package.
A brief look at running Raspberry Pi in a Haskell Cloud
Cloud Haskell brings some key contributions that, in one form or another, can play a major role in the next generation of cloud computing. And because Raspberry Pi, through its sheer low cost and capability, has the potential to gain the greatest reach of any embedded system.
Ready for serious experiments, but not yet for serious use.
Hackage
Source code and documentation
https://github.com/haskell-distributed/distributed-processThe New Cloud Haskell presentation by Duncan Coutts and Edsko de Vries delivered at the Haskell Implementors Workshop.