I'm no good at Ada, but I like the way it's syntax tries to guide you through reading the program. Now for something of comparative complexity in Clojure:
(def x (ref 1))
(defn increment [i]
(if (> i 0)
(
(dosync
(alter x inc)
)
(Thread/sleep 1)
(increment (- i 1))
)
)
)
(defn decrement [i]
(if (> i 0)
(
(dosync
(alter x dec)
)
(Thread/sleep 1)
(decrement (- i 1))
)
)
)
(defn printref [i]
(if (> i 0)
(
(dosync
(println (format "in printref %d" @x))
)
(Thread/sleep 1)
(printref (- i 1))
)
)
)
(future
(increment 10)
)
(future
(printref 15)
)
(future
(decrement 10)
)
Isn't this much nicer? It's not immediately obvious that x is an atomic variable, but aside from that it's a lot better than the Haskell example. It took me along the lines of 2-3 hours from never having touched a Lisp to writing this.
Here is the Haskell equivalent of your Clojure code:
import Data.IORef
import Control.Concurrent
increment _ 0 = return ()
increment x i = do
alter x succ
threadDelay 1000
increment x (i - 1)
decrement _ 0 = return ()
decrement x i = do
alter x pred
threadDelay 1000
decrement x (i - 1)
printref _ 0 = return ()
printref x i = do
val <- readIORef x
putStrLn ("in printref " ++ (show val))
threadDelay 1000
printref x (i - 1)
main = do
x <- newIORef 1
forkIO (increment x 10)
forkIO (printref x 15)
forkIO (decrement x 10)
threadDelay 100000
-- This is just a helper to more closely match the clojure
alter x fn = atomicModifyIORef' x (\y -> (fn y, ()))