This post shows a simple way to use the Reader Monad Transformer to:
The core code is mind-numbingly simple -- one type signature and two one-liner functions. In fact, it is so simple looking, it will take me three parts to explain why it is actually somewhat cool and useful. Some familiarity with the Reader monad is useful but not essential.
I expect that the technique shown in this series is applicable to other problems, but I am focusing on hyperlinks, because that is what is immediately useful to me. If you think up some other pratical uses, let me know and I will mention them.
First some header stuff. > {-# LANGUAGE DeriveDataTypeable, FlexibleContexts #-} > module Main where > import Control.Concurrent > import Control.Monad.Trans > import HAppS.Server hiding (method, dir) > import Text.XHtml > import Network.URIThe first step is to present the links as data types in the code. For example, let's imagine we have a simple image gallery. The gallery has two views:
Furthermore, when viewing an invidual image, we might view it:
Note that the data type only specifies which page to view. It does not include all of the information about the page, such as the filepath to the image, the image size etc. This data type only includes the type of information normally found in a URL.
Next we need some functions to turn our type into a
Link and back. Here we will make Link be a
simple String, but it could be something fancier, such as
Network.URI if desired.
For the first pass, we will just use show and
read with some extra functions to encode and decode
special characters which can not appear in a URI. Later we will see
how to implement showLink and readLink so
that they generate prettier and more user friendly links.
Next we implement a function which will interpret the
Gallery link and display the corresponding page:
There are two good things to note about gallery.
Strings. This means the compiler will catch typos,
mismatched types, missing arguments, and other similar errors at compile time.
showLink (ShowImage 1 Full) with showLink
True, the code will still compile without any errors. But, at
runtime, when you clicked on the link, it will try to find a match for
True and get a 404.
Additionally, if we try to use the Gallery library in two
places in a larger site, the generated URIs will be wrong and
non-unique. For example, imagine if we had a site like:
> data OurSite
> = HomePage
> | MyGallery Gallery
> | YourGallery Gallery
> deriving (Read, Show)
In the next post we will see how to
Iaddress these two issues.
gallery example. It uses HAppS, but could easily be
adapted to use Network.CGI.
> data Site link a
> = Site { handleLink :: link -> a
> , defaultPage :: link
> }
> runSite :: (Read link) => Site link a -> Link -> Maybe a
> runSite site linkStr =
> let mLink =
> case linkStr of
> "" -> Just (defaultPage site)
> _ -> readLink linkStr
> in
> fmap (handleLink site) mLink
> simpleSite :: Site Gallery Html
> simpleSite =
> Site { handleLink = gallery "Jeremy"
> , defaultPage = Thumbnails
> }
> -- * Boilerplate code for running simpleSite via HAppS.
> -- Easily adaptable to Network.CGI, etc.
> implURL :: [ServerPartT IO Response]
> implURL =
> [ withRequest $ \rq ->
> let link = (concat (take 1 (rqPaths rq)))
> in
> do lift $ print link
> return . toResponse $ runSite simpleSite link
> ]
> main :: IO ()
> main =
> do tid <- forkIO $ simpleHTTP nullConf implURL
> putStrLn "running..."
> waitForTermination
> killThread tid