# LGtk

### From HaskellWiki

(new references & running) |
m (→Reference creation API) |
||

Line 175: | Line 175: | ||

* Derived <hask>MonadTrans</hask> instance of <hask>C</hask> to be able to lift operations in the <hask>m</hask> monad. |
* Derived <hask>MonadTrans</hask> instance of <hask>C</hask> to be able to lift operations in the <hask>m</hask> monad. |
||

− | Note that <hask>C</hask> is parameterized by a monad because |
+ | Note that <hask>C</hask> is parameterized by a monad because in this way it is easier to add other effects later. |

− | in this way it is easier to add other effects later. |
||

==== Running ==== |
==== Running ==== |

## Revision as of 13:19, 2 June 2013

## Contents |

## 1 What is it?

LGtk is a lens-based API for Gtk. LGtk is built on Gtk2Hs.

Most Haskellers would like to use a mature FRP-based API for creating graphical user interfaces. FRP may not be the best tool for special user interfaces, like interfaces which consists of buttons, checkboxes, combo boxes, text entries and menus only. LGtk has a lens-based API which fits better these user interfaces.

## 2 Semantics overview

The semantics of LGtk is given by a reference implementation. The reference implementation is given in the following stages.

### 2.1 Lenses

LGtk use simple lenses defined in the data-lens package:

newtype Lens a b = Lens { runLens :: a -> Store b a }

getL :: Lens a b -> a -> b

setL :: Lens a b -> b -> a -> a

lens :: (a -> b) -> (b -> a -> a) -> Lens a b

#### 2.1.1 Lens laws

The three well-known laws for lenses:

- get-set: ===set k (get k a) aa
- set-get: ===get k (set k b a)b
- set-set: ===set k b2 (set k b1 a)set k b2 a

Impure lenses, i.e. lenses which brake lens laws are allowed in certain places. Those places are explicitly marked and explained in this overview.

### 2.2 References

It is convenient to use lenses with the state monad (see this use case) and the reader monad.

Let's call a value with type**reference**of the state monad

There are several ways to model references in Haskell. LGtk models them as type classes with associated types, but that is just a technical detail.

#### 2.2.1 Types

Instead of giving a concrete implementation in Haskell, suppose that

- is a fixed type,s
- ~Ref :: * -> *, references are lenses fromLens sto the type of the referred value,s
- ~R :: * -> *, the reference reading monad is the reader monad overReader s,s
- ~S :: * -> *, the reference reading and writing monad is the state monad overState s.s

The three equality constraints are not exposed in the API.

#### 2.2.2 Operations

Exposed operations of- The instance ofMonadandSR

- The monad morphism between andRS

liftReadPart :: R a -> S a liftReadPart = gets . runReader

- Reference read

readRef :: Ref a -> R a readRef = reader . getL

- Reference write

writeRef :: Ref a -> a -> S () writeRef = modify . setL r

- Lens application on a reference

lensMap :: Lens a b -> Ref a -> Ref b lensMap = (.)

- Reference join

joinRef :: R (Ref a) -> Ref a joinRef = Lens . join . (runLens .) . runReader

- The unit reference

unitRef :: Ref () unitRef = lens (const ()) (const id)

**not**a reference because that would leak the program state

#### 2.2.3 Reference creation

There should be a possibility for new reference creation too.

New reference creation with a given initial value extends the state. For example, if the state isWe could model the type change of the state with an

indexed monad, but that would complicate both the API and the implementation too. Instead of changing the type of the state, we use an**extensible state**, a data type

empty :: S extend :: a -> State S (Lens S a)

such that the following laws hold:

- ===extend v >> return ()return ()
- ===extend v >>= liftReadPart . readRefreturn v

#### 2.2.4 Reference creation API

Let- ~C :: (* -> *) -> * -> *StateT S

The equality constraint is not exposed in the API. The following functions are exposed:

- New reference creation

newRef :: Monad m => a -> C m (Ref a) newRef v = mapStateT (return . runIdentity) $ extend v

- Lift reference read and write operations

liftWrite :: Monad m => S a -> C m a liftWrite = mapStateT (return . runIdentity)

- Derived instance ofMonadTransto be able to lift operations in theCmonad.m

#### 2.2.5 Running

The last missing function in the API is the running of the- Run the reference creation monad

runC :: Monad m => C m a -> m a runC x = runStateT x empty

### 2.3 Lens-trees

TODO

### 2.4 Effects

TODO

## 3 Examples

### 3.1 Hello World

main = runWidget $ label $ return "Hello World!"

### 3.2 Copy

The following applications presents an entry and a label below of it. When a text is entered in the entry, the label is changed to the entered text.

main = runWidget $ action $ do r <- newRef "enter text here" return $ vcat [ entry r , label $ readRef r ]

A crutial feature of LGtk is that you cannot change the value of references in this monad (you can read them though).

### 3.3 Addition

Two entries of integers and a label which shows the sum:

main = runWidget $ action $ do r1 <- newRef (12 :: Integer) r2 <- newRef 4 return $ vcat [ entryShow r1 , entryShow r2 , label $ liftM show $ liftM2 (+) (readRef r1) (readRef r2) ]

### 3.4 Complex examples

You can find more complex examples in the source code of LGtk. More examples will be presented here also.

## 4 Status

Features of lgtk-0.5

- The API is closed, you can safely use any constructs as far as you obey the documented laws.
- Support for asynchronous events. Using LGtk is a safe way for writing multithreaded Gtk applications.
- The semantics is getting stable but it is not yet documented.

TODO list:

- Add an efficient implementation for LGtk. LGtk has only a reference implementation currently.
- Add support for styles (layout, colors, etc).
- Support more Gtk constructs.

## 5 Demo application

You can try the demo application with the following commands:

cabal install gtk2hs-buildtools cabal install lgtk lgtkdemo

## 6 Changelog

### 6.1 lgtk-0.5.1

- Documentation fixes and cleanup
- Try to support Haskell Platform 2012.4.0.0

### 6.2 lgtk-0.5

- Do not use monadic lenses any more.
- Support for asynchronous events.
- Lazily created tabs.
- Unactive tabs are really unactive (event handlers are detached).
- File references watch the files. When the file changes, the GUI is updated.
- References with inherent identity (makes defining auto-sensitive buttons easier)
- Experimental support for colored buttons.
- More examples in the demo application.
- Lots of inner changes.

## 7 External links

Related Stackoverflow questions:

Reddit comments: