Haskell on a Horse ================== Haskell on a Horse (HoH) is a combinatorial web framework for the programming language Haskell. I developed it in 2010, but other responsibilities prevented me from ever really finishing it - at this point I have moved on to other projects. The project remains interesting for various reasons - there is a coroutine implementation in Control/Arrow/Transformer/Automaton/Monad, the LabeledArrow and MaybeAutomaton classes are unique as far as I know, and the compositional handling of web forms is, as far as I know, more sophisticated than any other system. If you'd like to browse the code, it is available on github now. Installing and Using HoH ------------------------ cabal install on-a-horse > {-#LANGUAGE Arrows, QuasiQuotes, ScopedTypeVariables, NoMonomorphismRestriction #-} > import Web.Horse > import Control.Applicative > import Control.Arrow > import Control.Monad > import Control.Monad.Cont > import Data.Maybe > import Network.Wai.Handler.Warp (run) > import Data.Monoid > import qualified Data.Set as S > import Data.List.Split (splitOn) > import Control.Arrow.Transformer.All > import Text.Pandoc Atomic Components ------------------- An HoH application is built up from atomic components. A component is a complete HoH application all by itself: it can render itself, and respond to input.
> > ex1 = proc url -> do > (fo,num::Maybe Integer) <- readForm "enter a number" -< () > returnA -< wrapForm fo > | EXAMPLE |
> ex2 :: HoHMay Url String
> ex2 = proc url -> do
> (fo1, oper) <- enumForm "operation"
> [("times", (*)),
> ("plus", (+))] -< ()
> (fo2, x::Maybe Integer) <- readForm "x" -< ()
> (fo3, y::Maybe Integer) <- readForm "y" -< ()
> let result = show <$> (oper <*> x <*> y)
> returnA -< wrapForm $ mconcat [
> "Calculate a number!",
> " ", > fo1, fo2, fo3, > "Result:", > fromMaybe "" result, > " " > ] | EXAMPLE |
> ex3 :: HoHMay Url String > ex3 = formSum "example to run" [("example 1",ex1),("example 2",ex2)] mempty > >>> arr wrapForm | EXAMPLE |
> ex4 = proc url -> do
> (fo,result) <- term "expression" -< ()
> returnA -< wrapForm $ mconcat [fo, "Result:", maybe "" show result, " "] > where > term :: String -> HoHMay () (FormOut, Maybe Integer) > term label = catchMayAuto $ formSum label > [("number", number label), > ("add",oper label "add" (+)), > ("multiply",oper label "multiply" (*))] (mempty, Nothing) > > number :: String -> HoHErrMay (HoH () (FormOut, Maybe Integer)) > () (FormOut, Maybe Integer) > number termLabel = proc () -> do > fo1 <- linkForm "cancel" (term termLabel) -< () > (fo2,x) <- readForm "number" -< () > returnA -< (fo1 `mappend` fo2, x) > > oper termLabel label f = proc () -> do > (fo1) <- linkForm "cancel" (term termLabel) -< () > (fo2,x) <- liftError (term "x") -< () > (fo3,y) <- liftError (term "y") -< () > out <- returnA -< mconcat $ [" ", fo1, label, " ", fo2, fo3] > returnA -< (out, f <$> x <*> y) | EXAMPLE |
> ex5 = proc url -> do > (dispatch $ staticUrls fourOhFour $ > [("", urls), > ("ex1", ex1), > ("ex2", ex2), > ("ex3", ex3), > ("ex4", ex4)]) -< (url,url) | EXAMPLE |