diff --git a/exec/Cell.hs b/exec/Cell.hs
new file mode 100644
--- /dev/null
+++ b/exec/Cell.hs
@@ -0,0 +1,16 @@
+{-# LANGUAGE ApplicativeDo     #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+import Typed.Spreadsheet
+
+main :: IO ()
+main = cellUI "Example program" $ do
+    a <- checkBox   "a"
+    b <- spinButton "b" 1
+    c <- spinButton "c" 0.1
+    d <- entry      "d"
+    return
+        [ ("a"    , display  a     )
+        , ("b + c", display (b + c))
+        , ("d"    , display  d     )
+        ]
diff --git a/exec/Graphics.hs b/exec/Graphics.hs
--- a/exec/Graphics.hs
+++ b/exec/Graphics.hs
@@ -1,6 +1,6 @@
+{-# LANGUAGE ApplicativeDo     #-}
 {-# LANGUAGE OverloadedStrings #-}
 
-import Diagrams.Backend.Cairo (Cairo)
 import Diagrams.Prelude
 import Typed.Spreadsheet
 
@@ -16,13 +16,9 @@
 toColor Purple = purple
 
 main :: IO ()
-main = graphicalUI "Example program" logic
-  where
-    logic = combine <$> radioButton      "Color"        Red [Orange .. Purple]
-                    <*> spinButtonAt 100 "Radius"       1
-                    <*> spinButton       "X Coordinate" 1
-                    <*> spinButton       "Y Coordinate" 1
-
-    combine :: AColor -> Double -> Double -> Double -> Diagram Cairo
-    combine color r x y =
-        circle r # fc (toColor color) # translate (r2 (x, y))
+main = graphicalUI "Example program" $ do
+    color <- radioButton                   "Color"        Red [Orange .. Purple]
+    r     <- spinButtonAt    100           "Radius"       1
+    x     <- hscaleWithRange (-200) 200 0  "X Coordinate" 10
+    y     <- vscaleWithRange (-200) 200 0  "Y Coordinate" 10
+    return (circle r # fc (toColor color) # translate (r2 (x, y)))
diff --git a/exec/Text.hs b/exec/Text.hs
--- a/exec/Text.hs
+++ b/exec/Text.hs
@@ -1,14 +1,12 @@
+{-# LANGUAGE ApplicativeDo     #-}
 {-# LANGUAGE OverloadedStrings #-}
 
-import Control.Applicative
 import Typed.Spreadsheet
 
 main :: IO ()
-main = textUI "Example program" logic
-  where
-    logic = combine <$> checkBox   "a"
-                    <*> spinButton "b" 1
-                    <*> spinButton "c" 0.1
-                    <*> entry      "d"
-
-    combine a b c d = display (a, b + c, d)
+main = textUI "Example program" $ do
+    a <- checkBox   "a"
+    b <- spinButton "b" 1
+    c <- spinButton "c" 0.1
+    d <- entry      "d"
+    return (display (a, b + c, d))
diff --git a/src/Typed/Spreadsheet.hs b/src/Typed/Spreadsheet.hs
--- a/src/Typed/Spreadsheet.hs
+++ b/src/Typed/Spreadsheet.hs
@@ -1,22 +1,21 @@
 {-# LANGUAGE ExistentialQuantification  #-}
 {-# LANGUAGE RankNTypes                 #-}
+{-# LANGUAGE ApplicativeDo              #-}
 
 -- | The following program:
 --
+-- > {-# LANGUAGE ApplicativeDo     #-}
 -- > {-# LANGUAGE OverloadedStrings #-}
 -- > 
--- > import Control.Applicative
 -- > import Typed.Spreadsheet
 -- > 
 -- > main :: IO ()
--- > main = textUI "Example program" logic
--- >   where
--- >     logic = combine <$> checkBox   "a"
--- >                     <*> spinButton "b" 1
--- >                     <*> spinButton "c" 0.1
--- >                     <*> entry      "d"
--- > 
--- >     combine a b c d = display (a, b + c, d)
+-- > main = textUI "Example program" $ do
+-- >     a <- checkBox   "a"
+-- >     b <- spinButton "b" 1
+-- >     c <- spinButton "c" 0.1
+-- >     d <- entry      "d"
+-- >     return (display (a, b + c, d))
 --
 -- ... creates a user interface that looks like this:
 --
@@ -27,27 +26,11 @@
 --
 -- <<http://i.imgur.com/TTxgSwN.png User interface after user input>>
 --
--- Once @ghc-8.0@ is out then you can simplify the above program even further
--- using the `ApplicativeDo` extension:
---
--- > {-# LANGUAGE ApplicativeDo     #-}
--- > {-# LANGUAGE OverloadedStrings #-}
--- > 
--- > import Typed.Spreadsheet
--- > 
--- > main :: IO ()
--- > main = textUI "Example program" (do
--- >     a <- checkBox   "a"
--- >     b <- spinButton "b" 1
--- >     c <- spinButton "c" 0.1
--- >     d <- entry      "d"
--- >     return (display (a, b + c, d)) )
---
 -- This library also supports graphical output, like in the following program:
 --
+-- > {-# LANGUAGE ApplicativeDo     #-}
 -- > {-# LANGUAGE OverloadedStrings #-}
 -- > 
--- > import Diagrams.Backend.Cairo (Cairo)
 -- > import Diagrams.Prelude
 -- > import Typed.Spreadsheet
 -- > 
@@ -63,16 +46,12 @@
 -- > toColor Purple = purple
 -- > 
 -- > main :: IO ()
--- > main = graphicalUI "Example program" logic
--- >   where
--- >     logic = combine <$> radioButton       "Color"    Red [Orange .. Purple]
--- >                     <*> spinButtonAt 100  "Radius"       1
--- >                     <*> spinButton        "X Coordinate" 1
--- >                     <*> spinButton        "Y Coordinate" 1
--- > 
--- >     combine :: AColor -> Double -> Double -> Double -> Diagram Cairo
--- >     combine color r x y =
--- >         circle r # fc (toColor color) # translate (r2 (x, y))
+-- > main = graphicalUI "Example program" $ do
+-- >     color <- radioButton      "Color"        Red [Orange .. Purple]
+-- >     r     <- spinButtonAt 100 "Radius"       1
+-- >     x     <- spinButton       "X Coordinate" 1
+-- >     y     <- spinButton       "Y Coordinate" 1
+-- >     return (circle r # fc (toColor color) # translate (r2 (x, y)))
 --
 -- This produces a canvas that colors, resizes, and moves a circle in response
 -- to user input:
@@ -84,9 +63,8 @@
 -- * You build primitive `Updatable` values using `checkBox`, `spinButton`,
 --   `entry`, or `radioButton`, each of which corresponds to a control on the
 --   left panel of the user interface
--- * You transform or combine `Updatable` values using `Functor` and
---   `Applicative` operations.  Composite values update whenever one of their
---   substituent values update
+-- * Combine `Updatable` values using @ApplicativeDo@ notation.  Composite values
+--   update whenever one of their substituent values update
 -- * You consume an @(`Updatable` `Text`)@ value using `textUI`, which displays
 --   the continuously updating value in the right panel of the user interface
 --
@@ -96,9 +74,13 @@
 -- > $ stack build --install-ghc             # Builds the executable
 -- > $ stack exec typed-spreadsheet-example  # Runs the executable
 --
--- That project includes the code for the above example in @exec/Main.hs@.  Just
--- modify that file and rebuild to play with the example.
+-- ... or if you are using OS X, then build the project using:
 --
+-- > $ stack --stack-yaml=osx.yaml build --install-ghc
+--
+-- That project includes the code for the above examples in the @exec/@
+-- subdirectory.  Just modify that file and rebuild to play with the example.
+--
 -- NOTE: You must compile your program with the @-threaded@ flag.  The example
 -- project takes care of this.
 --
@@ -108,6 +90,7 @@
     -- * Types
       Updatable
     , textUI
+    , cellUI
     , graphicalUI
 
     -- * Controls
@@ -119,6 +102,12 @@
     -- * Controls with Defaults
     , checkBoxAt
     , spinButtonAt
+    , hscale
+    , hscaleAt
+    , hscaleWithRange
+    , vscale
+    , vscaleAt
+    , vscaleWithRange
     , entryAt
 
     -- * Utilities
@@ -129,23 +118,22 @@
     ) where
 
 import Control.Applicative
-import Control.Concurrent (threadDelay)
 import Control.Concurrent.STM (STM)
 import Control.Foldl (Fold(..))
 import Control.Monad.IO.Class (liftIO)
-import Data.Monoid
 import Data.String (IsString(..))
 import Data.Text (Text)
 import Diagrams.Backend.Cairo (Cairo)
-import Diagrams.Backend.Gtk (renderToGtk)
 import Diagrams.Prelude (Diagram, r2, reflectY, translate, (#))
 import Lens.Micro (_Left, _Right)
 import Graphics.UI.Gtk (AttrOp((:=)))
 
+import qualified Control.Concurrent
 import qualified Control.Concurrent.STM   as STM
-import qualified Control.Concurrent.Async as Async
-import qualified Control.Foldl            as Fold
-import qualified Data.Text                as Text
+import qualified Control.Concurrent.Async
+import qualified Control.Foldl
+import qualified Data.Text
+import qualified Diagrams.Backend.Gtk
 import qualified Graphics.UI.Gtk          as Gtk
 
 data Cell a = forall e . Cell (IO (STM e, Fold e a))
@@ -162,7 +150,10 @@
           where
             input = fmap Left inputF <|> fmap Right inputX
 
-            fold = Fold.handles _Left foldF <*> Fold.handles _Right foldX
+            fold  = do
+                f <- Control.Foldl.handles _Left foldF
+                x <- Control.Foldl.handles _Right foldX
+                return (f x)
 
 -- | An updatable input value
 data Updatable a = Updatable (Control -> Cell a)
@@ -225,10 +216,12 @@
 
 -- | Use a `Control` to obtain updatable input `Updatable`s
 data Control = Control
-    { _checkBoxAt   :: Bool -> Text -> Cell Bool
-    , _spinButtonAt :: Double -> Text -> Double -> Cell Double
-    , _entryAt      :: Text -> Text -> Cell Text
-    , _radioButton  :: forall a . Show a => Text -> a -> [a] -> Cell a
+    { _checkBoxAt      :: Bool -> Text -> Cell Bool
+    , _spinButtonAt    :: Double -> Text -> Double -> Cell Double
+    , _hscaleWithRange :: Double -> Double -> Double -> Text -> Double -> Cell Double
+    , _vscaleWithRange :: Double -> Double -> Double -> Text -> Double -> Cell Double
+    , _entryAt         :: Text -> Text -> Cell Text
+    , _radioButton     :: forall a . Show a => Text -> a -> [a] -> Cell a
     }
 
 -- | Build a `Text`-based user interface
@@ -253,8 +246,10 @@
         vAdjust <- Gtk.textViewGetVadjustment textView
         scrolledWindow <- Gtk.scrolledWindowNew (Just hAdjust) (Just vAdjust)
         Gtk.set scrolledWindow
-            [ Gtk.containerChild           := textView
-            , Gtk.scrolledWindowShadowType := Gtk.ShadowIn
+            [ Gtk.containerChild                 := textView
+            , Gtk.scrolledWindowShadowType       := Gtk.ShadowIn
+            , Gtk.scrolledWindowHscrollbarPolicy := Gtk.PolicyAutomatic
+            , Gtk.scrolledWindowVscrollbarPolicy := Gtk.PolicyAutomatic
             ]
         Gtk.boxPackStart hBox scrolledWindow Gtk.PackGrow 0
         return textBuffer
@@ -263,6 +258,57 @@
     processTextEvent textBuffer txt =
         Gtk.set textBuffer [ Gtk.textBufferText := txt ]
 
+-- | Build a cell-based user interface
+cellUI
+    :: Text
+    -- ^ Window title
+    -> Updatable [(Text, Text)]
+    -- ^ Program logic
+    -> IO ()
+cellUI = ui cellSetup processCellEvent
+  where
+    cellSetup :: Gtk.HBox -> IO Gtk.VBox
+    cellSetup hBox = do
+        vbox <- Gtk.vBoxNew False 5
+        Gtk.boxPackStart hBox vbox Gtk.PackGrow 0
+        return vbox
+
+    processCellEvent :: Gtk.VBox -> [(Text, Text)] -> IO ()
+    processCellEvent vbox keyVals = do
+        cells <- Gtk.containerGetChildren vbox
+        mapM_ (Gtk.containerRemove vbox) cells
+
+        let createCell (key, val) = do
+                textView   <- Gtk.textViewNew
+                textBuffer <- Gtk.get textView Gtk.textViewBuffer
+                Gtk.set textView
+                    [ Gtk.textViewEditable      := False
+                    , Gtk.textViewCursorVisible := False
+                    ]
+                Gtk.set textBuffer [ Gtk.textBufferText := val ]
+                hAdjust <- Gtk.textViewGetHadjustment textView
+                vAdjust <- Gtk.textViewGetVadjustment textView
+                scrolledWindow <- do
+                    Gtk.scrolledWindowNew (Just hAdjust) (Just vAdjust)
+                Gtk.set scrolledWindow
+                    [ Gtk.containerChild :=
+                        textView
+                    , Gtk.scrolledWindowShadowType :=
+                        Gtk.ShadowIn
+                    , Gtk.scrolledWindowHscrollbarPolicy :=
+                        Gtk.PolicyAutomatic
+                    , Gtk.scrolledWindowVscrollbarPolicy :=
+                        Gtk.PolicyAutomatic
+                    ]
+                frame <- Gtk.frameNew
+                Gtk.set frame
+                    [ Gtk.containerChild := scrolledWindow
+                    , Gtk.frameLabel     := key
+                    ]
+                Gtk.boxPackStart vbox frame Gtk.PackNatural 0
+        mapM_ createCell keyVals
+        Gtk.widgetShowAll vbox
+
 -- | Build a `Diagram`-based user interface
 graphicalUI
     :: Text
@@ -284,7 +330,8 @@
         (w, h) <- Gtk.widgetGetSize drawingArea
         let w' = fromIntegral w / 2
         let h' = fromIntegral h / 2
-        renderToGtk drawWindow (diagram # reflectY # translate (r2 (w', h')))
+        let diagram' = diagram # reflectY # translate (r2 (w', h'))
+        Diagrams.Backend.Gtk.renderToGtk drawWindow diagram'
 
 -- | Shared logic for `textUI` and `graphicalUI`
 ui  :: (Gtk.HBox -> IO a)
@@ -334,8 +381,46 @@
 
             Gtk.boxPackStart vBox frame Gtk.PackNatural 0
             Gtk.widgetShowAll vBox
-            return (STM.takeTMVar tmvar, Fold.lastDef s0) )
+            return (STM.takeTMVar tmvar, Control.Foldl.lastDef s0) )
 
+    let __hscaleWithRange :: Double -> Double -> Double -> Text -> Double -> Cell Double
+        __hscaleWithRange minY maxY s0 label stepY = Cell (do
+            tmvar      <- STM.newEmptyTMVarIO
+            slider <- Gtk.hScaleNewWithRange minY maxY stepY
+            Gtk.set slider
+                [ Gtk.rangeValue    := s0
+                ]
+            _  <- Gtk.onRangeValueChanged slider (do
+                n <- Gtk.get slider Gtk.rangeValue
+                STM.atomically (STM.putTMVar tmvar n) )
+            frame <- Gtk.frameNew
+            Gtk.set frame
+                [ Gtk.containerChild := slider
+                , Gtk.frameLabel     := label
+                ]
+            Gtk.boxPackStart vBox frame Gtk.PackNatural 0
+            Gtk.widgetShowAll vBox
+            return (STM.takeTMVar tmvar, Control.Foldl.lastDef s0) )
+
+    let __vscaleWithRange :: Double -> Double -> Double -> Text -> Double -> Cell Double
+        __vscaleWithRange minY maxY s0 label stepY = Cell (do
+            tmvar      <- STM.newEmptyTMVarIO
+            slider <- Gtk.vScaleNewWithRange minY maxY stepY
+            Gtk.set slider
+                [ Gtk.rangeValue    := (-s0)
+                ]
+            _  <- Gtk.onRangeValueChanged slider (do
+                n <- Gtk.get slider Gtk.rangeValue
+                STM.atomically (STM.putTMVar tmvar (-n)) )
+            frame <- Gtk.frameNew
+            Gtk.set frame
+                [ Gtk.containerChild := slider
+                , Gtk.frameLabel     := label
+                ]
+            Gtk.boxPackStart hBox frame Gtk.PackNatural 0
+            Gtk.widgetShowAll hBox
+            return (STM.takeTMVar tmvar, Control.Foldl.lastDef s0) )
+
     let __checkBoxAt :: Bool -> Text -> Cell Bool
         __checkBoxAt s0 label = Cell (do
             checkButton <- Gtk.checkButtonNewWithLabel label
@@ -348,7 +433,7 @@
 
             Gtk.boxPackStart vBox checkButton Gtk.PackNatural 0
             Gtk.widgetShowAll vBox
-            return (STM.takeTMVar tmvar, Fold.lastDef s0) )
+            return (STM.takeTMVar tmvar, Control.Foldl.lastDef s0) )
 
     let __entryAt :: Text -> Text -> Cell Text
         __entryAt s0 label = Cell (do
@@ -368,7 +453,7 @@
 
             Gtk.boxPackStart vBox frame Gtk.PackNatural 0
             Gtk.widgetShowAll frame
-            return (STM.takeTMVar tmvar, Fold.lastDef s0) )
+            return (STM.takeTMVar tmvar, Control.Foldl.lastDef s0) )
 
     let __radioButton :: Show a => Text -> a -> [a] -> Cell a
         __radioButton label x xs = Cell (do
@@ -376,13 +461,13 @@
 
             vBoxRadio <- Gtk.vBoxNew False 5
 
-            let makeButton f a = do
-                    button <- f (show a)
+            let makeButton f y = do
+                    button <- f (show y)
                     Gtk.boxPackStart vBoxRadio button Gtk.PackNatural 0
                     _ <- Gtk.on button Gtk.toggled (do
                         active <- Gtk.get button Gtk.toggleButtonActive
                         if active
-                            then STM.atomically (STM.putTMVar tmvar a)
+                            then STM.atomically (STM.putTMVar tmvar y)
                             else return () )
                     return button
 
@@ -396,13 +481,15 @@
                 ]
             Gtk.boxPackStart vBox frame Gtk.PackNatural 0
             Gtk.widgetShowAll frame
-            return (STM.takeTMVar tmvar, Fold.lastDef x) )
+            return (STM.takeTMVar tmvar, Control.Foldl.lastDef x) )
 
     let control = Control
-            { _checkBoxAt   = __checkBoxAt
-            , _spinButtonAt = __spinButtonAt
-            , _entryAt      = __entryAt
-            , _radioButton  = __radioButton
+            { _checkBoxAt      = __checkBoxAt
+            , _spinButtonAt    = __spinButtonAt
+            , _hscaleWithRange = __hscaleWithRange
+            , _vscaleWithRange = __vscaleWithRange
+            , _entryAt         = __entryAt
+            , _radioButton     = __radioButton
             }
 
     doneTMVar <- STM.newEmptyTMVarIO
@@ -410,7 +497,7 @@
     let run (Cell m) = do
             (stm, Fold step begin done) <- Gtk.postGUISync m
             -- I don't know why this delay is necessary for diagrams output
-            threadDelay 200000
+            Control.Concurrent.threadDelay 200000
             let loop x = do
                     let b = done x
                     Gtk.postGUISync (process a b)
@@ -428,9 +515,9 @@
         Gtk.mainQuit
         return False ))
     Gtk.widgetShowAll window
-    Async.withAsync (run (k control)) (\a -> do
+    Control.Concurrent.Async.withAsync (run (k control)) (\s -> do
         Gtk.mainGUI
-        Async.wait a )
+        Control.Concurrent.Async.wait s )
 
 -- | A check box that returns `True` if selected and `False` if unselected
 checkBox
@@ -448,12 +535,30 @@
     -> Updatable Double
 spinButton = spinButtonAt 0
 
+-- | A `Double` horizontal slider
+hscale
+    :: Text
+    -- ^ Label
+    -> Double
+    -- ^ Step size
+    -> Updatable Double
+hscale = hscaleAt 0
+
+-- | A `Double` vertical slider
+vscale
+    :: Text
+    -- ^ Label
+    -> Double
+    -- ^ Step size
+    -> Updatable Double
+vscale = vscaleAt 0
+
 -- | A `Text` entry
 entry
     :: Text
     -- ^ Label
     -> Updatable Text
-entry = entryAt Text.empty
+entry = entryAt Data.Text.empty
 
 -- | A control that selects from one or more mutually exclusive choices
 radioButton
@@ -490,6 +595,60 @@
 spinButtonAt s0 label x =
     Updatable (\control -> _spinButtonAt control s0 label x)
 
+-- | Same as `hscaleButton` except that you can specify the initial state
+hscaleAt
+    :: Double
+    -- ^ Initial state
+    -> Text
+    -- ^ Label
+    -> Double
+    -- ^ Step size
+    -> Updatable Double
+hscaleAt = hscaleWithRange (fromIntegral (minBound :: Int)) (fromIntegral (maxBound :: Int))
+
+-- | Same as `hscaleButton` except that you can specify the range and initial state
+hscaleWithRange
+    :: Double
+    -- ^ Minimum value
+    -> Double
+    -- ^ Maximum value
+    -> Double
+    -- ^ Initial state
+    -> Text
+    -- ^ Label
+    -> Double
+    -- ^ Step size
+    -> Updatable Double
+hscaleWithRange b0 b1 s0 label x =
+    Updatable (\control -> _hscaleWithRange control b0 b1 s0 label x)
+
+-- | Same as `vscaleButton` except that you can specify the initial state
+vscaleAt
+    :: Double
+    -- ^ Initial state
+    -> Text
+    -- ^ Label
+    -> Double
+    -- ^ Step size
+    -> Updatable Double
+vscaleAt = vscaleWithRange (fromIntegral (minBound :: Int)) (fromIntegral (maxBound :: Int))
+
+-- | Same as `vscaleButton` except that you can specify the range and initial state
+vscaleWithRange
+    :: Double
+    -- ^ Minimum value
+    -> Double
+    -- ^ Maximum value
+    -> Double
+    -- ^ Initial state
+    -> Text
+    -- ^ Label
+    -> Double
+    -- ^ Step size
+    -> Updatable Double
+vscaleWithRange b0 b1 s0 label x =
+    Updatable (\control -> _vscaleWithRange control b0 b1 s0 label x)
+
 -- | Same as `entry` except that you can specify the initial state
 entryAt
     :: Text
@@ -501,34 +660,25 @@
 
 -- | Convert a `Show`able value to `Text`
 display :: Show a => a -> Text
-display = Text.pack . show
+display = Data.Text.pack . show
 
 -- $examples
 --
 -- Mortgage calculator:
 --
+-- > {-# LANGUAGE ApplicativeDo     #-}
 -- > {-# LANGUAGE OverloadedStrings #-}
 -- > 
--- > import Control.Applicative
--- > import Data.Monoid
--- > import Data.Text (Text)
 -- > import Typed.Spreadsheet
 -- > 
--- > payment :: Double -> Double -> Double -> Text
--- > payment mortgageAmount numberOfYears yearlyInterestRate
--- >     =  "Monthly payment: $"
--- >     <> display (mortgageAmount * (i * (1 + i) ^ n) / ((1 + i) ^ n - 1))
--- >   where
--- >     n = truncate (numberOfYears * 12)
--- >     i = yearlyInterestRate / 12 / 100
--- > 
--- > logic :: Updatable Text
--- > logic = payment <$> spinButton "Mortgage Amount"          1000
--- >                 <*> spinButton "Number of years"             1
--- >                 <*> spinButton "Yearly interest rate (%)"    0.01
--- > 
 -- > main :: IO ()
--- > main = textUI "Mortgage payment" logic
+-- > main = textUI "Mortgage payment" $ do
+-- >   mortgageAmount     <- spinButton "Mortgage Amount"          1000
+-- >   numberOfYears      <- spinButton "Number of years"             1
+-- >   yearlyInterestRate <- spinButton "Yearly interest rate (%)"    0.01
+-- >   let n = truncate (numberOfYears * 12)
+-- >   let i = yearlyInterestRate / 12 / 100
+-- >   return ("Monthly payment: $" <> display (mortgageAmount * (i * (1 + i) ^ n) / ((1 + i) ^ n - 1)))
 --
 -- Example input and output:
 --
@@ -538,7 +688,6 @@
 --
 -- > {-# LANGUAGE OverloadedStrings #-}
 -- > 
--- > import Data.Monoid
 -- > import Typed.Spreadsheet
 -- > 
 -- > noun = entry "Noun"
@@ -564,28 +713,25 @@
 --
 -- > {-# LANGUAGE OverloadedStrings #-}
 -- > 
--- > import Diagrams.Backend.Cairo (Cairo)
 -- > import Diagrams.Prelude
 -- > import Typed.Spreadsheet
 -- > 
 -- > main :: IO ()
--- > main = graphicalUI "Example program" logic
--- >   where
--- >     logic = combine <$> spinButtonAt 50  "Amplitude (Pixels)"   0.1
--- >                     <*> spinButtonAt 0.1 "Frequency (Pixels⁻¹)" 0.001
--- >                     <*> spinButtonAt 90  "Phase (Degrees)"      1
+-- > main = graphicalUI "Example program" $ do
+-- >     amplitude <- spinButtonAt 50  "Amplitude (Pixels)"   0.1
+-- >     frequency <- spinButtonAt 0.1 "Frequency (Pixels⁻¹)" 0.001
+-- >     phase     <- spinButtonAt 90  "Phase (Degrees)"      1
 -- > 
--- >     combine :: Double -> Double -> Double -> Diagram Cairo
--- >     combine amplitude frequency phase = strokeP (fromVertices points) <> axes
--- >       where
--- >         axes = arrowBetween (p2 (0, 0)) (p2 ( 100,    0))
+-- >     let axes = arrowBetween (p2 (0, 0)) (p2 ( 100,    0))
 -- >             <> arrowBetween (p2 (0, 0)) (p2 (-100,    0))
 -- >             <> arrowBetween (p2 (0, 0)) (p2 (   0,  100))
 -- >             <> arrowBetween (p2 (0, 0)) (p2 (   0, -100))
 -- > 
--- >         f x = amplitude * cos (frequency * x + phase * pi / 180)
+-- >     let f x = amplitude * cos (frequency * x + phase * pi / 180)
 -- > 
--- >         points = map (\x -> p2 (x, f x)) [-100, -99 .. 100]
+-- >     let points = map (\x -> p2 (x, f x)) [-100, -99 .. 100]
+-- > 
+-- >     return (strokeP (fromVertices points) <> axes)
 --
 -- Example input and output:
 --
@@ -595,21 +741,16 @@
 --
 -- > {-# LANGUAGE OverloadedStrings #-}
 -- > 
--- > import Diagrams.Backend.Cairo (Cairo)
 -- > import Diagrams.Prelude
 -- > import Diagrams.TwoD.Factorization (factorDiagram')
 -- > import Typed.Spreadsheet
 -- > 
 -- > main :: IO ()
--- > main = graphicalUI "Factor diagram" logic
--- >   where
--- >     logic = combine <$> spinButtonAt 3 "Factor #1" 1
--- >                     <*> spinButtonAt 3 "Factor #2" 1
--- >                     <*> spinButtonAt 3 "Factor #3" 1
--- > 
--- >     combine :: Double -> Double -> Double -> Diagram Cairo
--- >     combine x y z =
--- >         factorDiagram' [truncate x, truncate y, truncate z] # scale 10
+-- > main = graphicalUI "Factor diagram" $ do
+-- >     x <- spinButtonAt 3 "Factor #1" 1
+-- >     y <- spinButtonAt 3 "Factor #2" 1
+-- >     z <- spinButtonAt 3 "Factor #3" 1
+-- >     return (factorDiagram' [truncate x, truncate y, truncate z] # scale 10)
 --
 -- Example input and output:
 --
diff --git a/typed-spreadsheet.cabal b/typed-spreadsheet.cabal
--- a/typed-spreadsheet.cabal
+++ b/typed-spreadsheet.cabal
@@ -1,5 +1,5 @@
 Name: typed-spreadsheet
-Version: 1.1.0
+Version: 1.1.1
 Cabal-Version: >=1.8.0.2
 Build-Type: Simple
 License: BSD3
@@ -9,6 +9,7 @@
 Maintainer: Gabriel439@gmail.com
 Bug-Reports: https://github.com/Gabriel439/Haskell-Typed-Spreadsheet-Library/issues
 Synopsis: Typed and composable spreadsheets
+Tested-With: GHC == 8.0.2, GHC == 8.2.2
 Description:
     This library provides a typed and composable API for building spreadsheets.
     This differs from traditional spreadsheets in a few important ways:
@@ -31,35 +32,51 @@
 Library
     Hs-Source-Dirs: src
     Build-Depends:
-        base           >= 4      && < 5   ,
-        async          >= 2.0    && < 2.1 ,
-        diagrams-cairo >= 1.3    && < 1.4 ,
-        diagrams-gtk   >= 1.3    && < 1.4 ,
-        diagrams-lib   >= 1.3    && < 1.4 ,
-        foldl          >= 1.1    && < 1.2 ,
-        gtk            >= 0.13   && < 0.14,
-        microlens                   < 0.4 ,
+        base           >= 4.9    && < 5   ,
+        async          >= 2.0    && < 2.2 ,
+        diagrams-cairo >= 1.3    && < 1.5 ,
+        diagrams-gtk   >= 1.3    && < 1.5 ,
+        diagrams-lib   >= 1.3    && < 1.5 ,
+        foldl          >= 1.1    && < 1.3 ,
+        gtk            >= 0.13   && < 0.15,
+        microlens                   < 0.5 ,
         stm                         < 2.5 ,
         text                        < 1.3 ,
-        transformers  >= 0.2.0.0 && < 0.5
+        transformers  >= 0.2.0.0 && < 0.6
+    if os(darwin)
+      frameworks: Cocoa
     Exposed-Modules: Typed.Spreadsheet
     GHC-Options: -O2 -Wall
 
-Executable typed-spreadsheet-example
+Executable typed-spreadsheet-example-text
     Hs-Source-Dirs: exec
     Main-Is: Text.hs
     Build-Depends:
-        base >= 4 && < 5  ,
-        text         < 1.3,
+        base >= 4.9 && < 5  ,
+        text           < 1.3,
         typed-spreadsheet
+    if os(darwin)
+      frameworks: Cocoa
     GHC-Options: -O2 -Wall -threaded
 
+Executable typed-spreadsheet-example-cell
+    Hs-Source-Dirs: exec
+    Main-Is: Cell.hs
+    Build-Depends:
+        base >= 4.9 && < 5  ,
+        text           < 1.3,
+        typed-spreadsheet
+    if os(darwin)
+      frameworks: Cocoa
+    GHC-Options: -Wall -threaded
+
 Executable typed-spreadsheet-example-graphics
     Hs-Source-Dirs: exec
     Main-Is: Graphics.hs
     Build-Depends:
         base           >= 4   && < 5  ,
-        diagrams-cairo >= 1.3 && < 1.4,
-        diagrams-lib   >= 1.3 && < 1.4,
+        diagrams-lib   >= 1.3 && < 1.5,
         typed-spreadsheet
+    if os(darwin)
+      frameworks: Cocoa
     GHC-Options: -O2 -Wall -threaded
