PropLang

From HaskellWiki
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

A design for a GUI library which is more like Haskell and less like C. To be written over Gtk2Hs.

Link: http://www.cse.unsw.edu.au/~chak/haskell/ports/

Thoughts by

Neil Mitchell, Duncan Coutts


For a darcs repo see: http://www.cs.york.ac.uk/fp/darcs/proplang/

In particular check out Sample.hs, I am particularly proud of the word count:

sb!text =< with1 (txt!text) (\x ->
    "Word count: " ++ show (length $ words x))

The Var concept

This is the low level stuff, on which the library will be built

data Var a = ...
data Notify = ...
get :: Var a -> IO a
set :: Var a -> a -> IO ()
addNotify :: Var a -> (a -> IO ()) -> IO Notify
remNotify :: Notify -> IO ()
newVar :: a -> IO (Var a)

A concrete implementation of Var

One thing to avoid, global state that needs a specific init function

data Var a = Var {value :: IORef a,
                  notifyId :: IORef Integer,
                  notifys :: IORef [(Integer, a -> IO ())],
                  source :: IORef (Maybe Notify)}
data Notify = Notify {notifyId :: Integer, notifys :: IORef [(Integer, a -> IO ())]}
newVar :: a -> IO (Var a)
newVar x = do v <- newIORef x
              n <- newIORef []
              c <- newIORef 0
              a <- newIORef Nothing
              return $ Var v c n a
get :: Var a -> IO a
get var = readIORef (value var)
set :: Var a -> a -> IO ()
set var x = do n <- readIORef (notifys var)
               writeIORef (value var) x
               mapM_ (\(a,b) -> b x) n
addNotify :: Var a -> (a -> IO ()) -> IO Notify
addNotify var f = do n <- readIORef (notifys var)
                     c <- readIORef (notifyId var)
                     writeIORef (notifyId var) (c+1)
                     writeIORef (notifys var) ((c, f) : n)
                     return $ Notify c (notifys var)
remNotify :: Notify -> IO ()
remNotify notify = do n <- readIORef (notifys notify)
                      writeIORef (notifys notify) (filter (\x -> fst x /= notifyId notify) n)

Object layering

textBox!text -< "test"
filename <- newVar Nothing
addNotify filename hatCover
lbl!text =< with filename $ \x ->
                 case x of
                     Nothing -> "Select a file"
                     Just x -> "Loaded: " ++ x


where

(!) :: GtkObject -> GtkProp -> Var a -- ignoring lots of details here
(-<) :: Var a -> a -> IO ()
(=<) :: Var a -> Action a b -> IO ()
with :: Var a -> (a -> b) -> Action a b

Implementation of Object Layering

data Action a b = Action (Var a) (a -> b)
with :: Var a -> (a -> b) -> Action a b
with var f = Action var f
(-<) :: Var a -> a -> IO ()
(-<) var val = set var val
(=<) :: Var a -> Action a -> IO ()
(=<) dest (Act src f) = do srcOld <- readIORef (source dest)
                           when (isJust srcOld) $ remNotify (fromJust srcOld)
                           note <- addNotify src (\x -> set dest (f x))
                           writeIORef (source dest) (Just note)

Implementation of Gtk Layering

class TextProvider a where
    text :: a -> Var String
instance TextProvider TextView where
    text x = ...
txt :: TextView
(!) :: a -> (a -> b) -> b
object ! prop = prop object
txt!text :: Var String