Showing posts with label Haskell. Show all posts
Showing posts with label Haskell. Show all posts

Wednesday, October 02, 2013

What I have been doing: Runtime templates and Content Management


Hi,

There are two exciting things that I´m being doing lately: Content management has been improved a lot. Now the editors can edit large texts at runtime and see the result instantly. They have an edition panel with all the ordinary functionalities including uploading and linking images, edition of raw HTML and so on. Different users can have permissions for different sections. See the content of the home page of the MFlow demos. It has been created with this content management facility at runtime. The content management demo shows how it works.

After you have logged with the right user, to edit the text click on them. immediately, the panel above is activated and the content can be edited. At the end, clicking the save button, the edition facility and the panel disappear and the editor see the exact layout of the page. To edit it again, just refresh the page. The content is published immediately. for the public. The content is saved in the texts folder.

Very related with this, but more exciting and powerful, is the possibility to modify the layout of the active components at run-time. This means that no longer is necessary to define a layout before compilation for a formulary,  or for the arrangement of different widgets. Just create them without layout, and later the stylist will arrange the layout and the texts when the application is already tested. Then the layout never pollutes the code, and it may be decoupled also in time. he layout can be edited in a more powerful editor and inserted again and so on. As long as the designer do not modify the tags of forms and links created by the application, everithing goes fine. It can insert wathever content, formatting, apply styles etc.

This does not end here. There may be more than one layout,with more or less text, advertising etc depending o the device. For example,  a slim layout for mobile phones, other more heavy for PCs etc. This is something that I´m just developing now. T

Friday, August 30, 2013

MFlow using persistent with sqlite backend

There are excellent libraries that I want to make interoperable with MFlow one of them is Persistent. It allows to define backend-independent data layers. In the previous post I mentioned an example of direct integration of TCache -the cache of MFlow- with Amazon web services. In this example I will show how MFlow and Persistent directly interact. 

Since in this case, the database is a in memory instance of sqlite, It does not make sense to cache data. But since Persistent can interact with remote SQL and nonSQL databases, I need to integrate TCache with Persistent for caching in the near future.

But first, this example illustrates the use of MFlow with Persistent. The example is at:


The code is taken from http://www.yesodweb.com/book/persistent by modifying the first example and making some guesses by looking at the prostgresSQL version , both are console-oriented programs.

Note how little additions are necessary to change a console application of the sample to a MFlow application.

The example has a navigation of four pages and you can go forward and backward. While the flow looks like an ordinary imperative program, yo can go back and fort and to introduce any bookmark without producing navigation errors.

Additionally you can press the back button, change the form input and see how the responses match the register values. 


This is the code:

{-# LANGUAGE EmptyDataDecls    #-}
{-# LANGUAGE FlexibleContexts  #-}
{-# LANGUAGE GADTs             #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes       #-}
{-# LANGUAGE TemplateHaskell   #-}
{-# LANGUAGE TypeFamilies      #-}
{-# LANGUAGE NoMonomorphismRestriction #-}

module MFlowPersistent

where

import           MFlow.Wai.Blaze.Html.All
import           Control.Monad.IO.Class  (liftIO)
import           Database.Persist
import           Database.Persist.Sqlite
import           Database.Persist.TH

import           System.IO.Unsafe

import           Menu



share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Person
    name String
    age Int Maybe
    deriving Show
BlogPost
    title String
    authorId PersonId
    deriving Show
|]

-- Uncomment this to run the example alone
--main= do
--  migratesqlite
--  runNavigation "" . transientNav $ mFlowPersistent
-- 
--askm= ask 

  
pool= unsafePerformIO $ createSqlitePool ":memory:" 10

runSQL sql= liftIO $  runSqlPersistMPool sql pool

migratesqlite= runSQL $ runMigration migrateAll

mFlowPersistent ∷  FlowM Html IO ()
mFlowPersistent = do
    (name, age) ← askm $ (,) 
                         <$> getString Nothing <! hint "your name" 
                         <++ br
                         <*> getInt    Nothing <! hint "your age"
                         <** br
                         ++> submitButton "enter"
                         
    userId ←  runSQL  $ insert $ Person name $ Just age

    post ←  askm $ getString Nothing <! hint "your post" <** submitButton "enter"
    runSQL  $ insert $ BlogPost post userId

    oneUserPost ←  runSQL  $ selectList [BlogPostAuthorId ==. userId] [LimitTo 1]

    askm $   b << show (oneUserPost ∷  [Entity BlogPost]) 
         ++> br 
         ++> wlink () << b  "click here"

    user ←  runSQL  $ get userId

    askm $   b << show (user ∷  Maybe Person) 
         ++> br ++> wlink ()  << b  "click here"
    where
    hint h=  [("placeholder",h)]

Thursday, August 29, 2013

Using Amazon Web Services with TCache and MFlow

The code of this example is identical to any one for persistence in files that you can find here except the procedure  setAmazonSimpleDB that set the default persistence in Amazon simpleDB. 

Here is the example running:

http://mflowdemo.herokuapp.com/noscript/database

As ever, MFlow permits to address all the pages in the flow with a single bookmark. You just enter the appropriate path and parameters. For example this URL:

http://mflowdemo.herokuapp.com/noscript/database/newtext

Present the entry form, that is the second page in the demo. And this URL:

http://mflowdemo.herokuapp.com/noscript/database/newtext?p0= text to enter

Fill the text box of the entry form, insert the text in the database and return to the first page again, since the demo has a loop.

Default persistence means that each register is stored in a small blob somewhere, either in a file -by default- or in another storage. For small blobs identified by keys,  Amazon simpleDB is better than  S3. 

The default persistence is defined in the setDefaultPersist and setPersist. While the former -as its name says- set the default for any kind of data, this latter is per-datatype. It is a method defined in the Serializable instance in the DefaultPersistence module. The blob of each register is read and written by TCache and converted to a haskell register under a  DBRef reference, in the STM monad. DBRefs follows the semantics of the TVar references.

TCache besides caching the registers, it permits querying and indexing them by a relational-like syntax using haskell register field names (see the query defined below in allTexts). The indexes used for querying are also registers that are stored and retrieved using the default persist mechanism.  That means that the registers that are not used are discarded from the cache, and the modified indexes are stored in the persistent storage automatically, in this case, in SimpleDB

Caching and querying local indexes improves response time and reduces the number of accesses to the paid cloud infrastructure, so it reduces costs.

I´m not fully satisfied with the default persistence set in setAmazonSimpleDB  I need to optimize the storage and the access using more features of  AWS simpleDB and mix it with Amazon S3 for largue blogs, but this is a proof of concept.




This is the code:
{-# LANGUAGE DeriveDataTypeable, RecordWildCards #-}
module Database where
import MFlow.Wai.Blaze.Html.All hiding (select)

import Data.Typeable
import Data.TCache.IdexQuery
import Data.TCache.DefaultPersistence
import Data.TCache.Memoization
import Data.Monoid
import Menu 
import Data.String
import Aws
import Aws.SimpleDb hiding (select)
import qualified Data.Text as T
import Data.Text.Encoding
import Data.ByteString.Lazy(toChunks,fromChunks)
import Network

import Debug.Trace
(!>)= flip trace

data  MyData= MyData{idnumber ∷ Int, textdata ∷  T.Text} deriving (Typeable, Read, Show)      -- that is enough for blob persistence

instance Indexable MyData where  
   key=  show . idnumber    -- to notify what is the key of the register
   defPath = const ""
   
data Options= NewText  | Exit deriving (Show, Typeable) 


main= do
  setAmazonSimpleDB
  syncWrite  $ Asyncronous 120 defaultCheck  1000
  index idnumber
  runNavigation "" $ transientNav $ do
     all ←  allTexts
     r ←  ask $ listtexts all
     case r of
         NewText → do
              text ←  ask $   p << "insert the text" 
                           ++> getMultilineText "" <++ br
                           <** submitButton "enter"

              -- store the name in the cache 
              -- (later will be written to disk automatically)
              liftIO . atomically . newDBRef $ MyData (length all) text 

         Exit → return ()
     where 

     menu=   wlink NewText   << p << "enter a new text" <|> 
             wlink Exit      << p << "exit to the main menu"
               
     listtexts all  =  do
           h3 << "list of all texts"
           ++> mconcat[p <<  t | t ←  all]
           ++> menu
           <++ b << "or the back button for a new database action"

     allTexts= liftIO . atomically . select textdata $ idnumber .>=. (0 ∷  Int) 
     
sdbCfg =  defServiceConfig

domain = fromString "mflowdemotest"

setAmazonSimpleDB = withSocketsDo $ do
 cfg ←  baseConfiguration
-- simpleAws cfg sdbCfg $ deleteDomain domain 
 simpleAws cfg sdbCfg $ createDomain domain  -- delete once created
 setDefaultPersist $ Persist{
   readByKey= λkey → withSocketsDo $ do
       r ←  simpleAws cfg sdbCfg $ getAttributes (T.pack key) domain 
       case r of
        GetAttributesResponse [ForAttribute _ text] → return $ Just   
             $ fromChunks [encodeUtf8 text]
        _ → return Nothing,
        
   write= λkey str → withSocketsDo $ do
       simpleAws cfg sdbCfg 
                     $ putAttributes  (T.pack key)  
                       [ForAttribute tdata 
                        (SetAttribute 
                          (T.concat $ map decodeUtf8 $ toChunks str)
                             True)] domain
       return (),
   delete= λkey    → withSocketsDo $ do
     simpleAws cfg sdbCfg 
     $ deleteAttributes (T.pack key)  
       [ForAttribute tdata DeleteAttribute] domain
     return ()
     }


tdata= fromString "textdata"

Wednesday, August 14, 2013

How to use backtracking to present the main menu on every page for free

Still I´m exploring the possibilities of expressing the navigation of a web site by means of matching and backtracking. Using a monad with backtracking, and link + form parameters as the elements for the matching mechanism. That is how MFlow handles the web navigation. I increasingly find that this is the right paradigm that will be the standard if future web development. Event handling coding and all their abstruse configurations and hacks for proper state managemnt will be contemplated as the legacy of an ominous past  that the Humanity had to travel before finding the freedom-under-control of the monadic utopia  ;)       

As an example of how natural is the transformation of web navigation requirements in terms of tracking and backtracking in a monadic, imperative-like code, I show you how I solved my last requirement:

I want to have the menu present in every page, in my demo at:  

http://mflowdemo.herokuapp.com

Now it has the main menu available for every page. Additionally, all the examples, including the persistent one (the shopping cart) are in a single flow.

I could have done thr first by just adding the menu as a widget more in each page, but this means that my code has to check for clicks in the menu on every page, besides the concrete code that I´m focused on.

So, if i have this code

r ←  page pagecode            (1)
normalAppflow r

To add a menu to each page I have to change the code in a way that look like:

r ←  ask $ fmap Left menu <|> fmap Right pagecode
case r of
   Right x        → normalAppflow x
   Left  menuitem → processitem menuitem

Or alternatively:
r ←  ask $ menu `waction` processItem **> pagecode
normalAppflow r

With:

processitem item= case item of item1 -> ... ...

In both cases, the menu items would be executed recursively. That is not good for the memory usage of the application since, to allow backtracking, the Flow monad is not tail recursive. The memory is freed when the timeout expires, but still it is not the best solution. It would be better backtrack to the menu before processing the option, so the data of this abandoned branch would be garbage collected.

Alternatively, I can put each demo in a page flow, where each page in the demo becomes a auto-refreshed widget under a single main page together with the menu, but that denaturalize some demos that are inherently made for page navigation. Additionally I don´t want to use such advanced thing as a page flows and auto-refreshing in the home page of a demo that I want to keep as simple and understandable as possible.

So I tried to use the backtracking mechanism in a way that when an item in the menu is clicked in any demo page, instead of checking for it and call again the menu, It backtracks to the menu page, where the flow will track the appropriate branch of execution depending on the menu item chosen.

Now I want not to code this manually, so instead I make my menu tell ask that he is some pages back and will care for the response, so page must initiate a backtraking. This is done with retry:

retry w= w >> modify (\st -> st{inSync=False})

inSync is an internal state parameter. It means that the server is in sync with the browser because the server found a parameter or link sent by the browser that match with the page that the server is now processing. because ask/page is forced to False by retry, he initiates a backtracking until some previous page match the web browser response.

Now the code becomes:

r ←  ask $ retry menu **> pagecode
normalAppflow r

or
r ←  pagem pagecode
normalAppflow r 

which is almost the same than the original code in (1).

With:

pagem pagecode= ask $ retry menu **> pagecode 

The **> operator is the applicative *> but the first ever executes the second parameter no matter if the first succeeded or not. Since all my pages use the same menu, then I can substitute ask and page by pagem, that knows implicitly about the menu. With this exception I have nothing more to change in my application. if no link of form of pagecode is clicked, then page will find itself not in sync, but actually, there have been a request for a link/form in the menu that will be handled by the menu page, back and down in the execution tree. That is why retry is called as such.

A page can have as many retried widgets as you like. It is important to have the retried widgets cached, since cached widgets maintain the parameter numbering for the web forms and the link deep appropriate for the place where they backtrack. Moreover a menu used in many pages is an inherent candidate for being cached, for performance reasons. I though about making these requirement explicit in the type system, but at this moment I find this alternative a bit overengineered.

This is how the navigation monad example would look like with these modifications. The essential changes are in bold:
import MFlow.Wai.Blaze.Html.All
        
main= runNavigation "" . transientNav $ do
  option ←  ask  menu1 
  case option of
    "1" → do
           pagem $ wlink "2" << contentFor "1"
           pagem $ wlink "3" << contentFor "2"
           pagem $ wlink "4" << contentFor "3"

    "a" → do
           pagem $ wlink "b" << contentFor "a"
           pagem $ wlink "c" << contentFor "b"
           pagem $ wlink "d" << contentFor "c"

  pagem $ wlink ()  << p << "back to the first page"

menu1 =  wcached "menu" 0 $ wlink "a" << b << "letters " <++ i << "or "   <|> wlink "1" << b << "numbers"

pagem  pagecode =page $ retry menu1 **> pagecode
     
contentFor x= do
        p << "page for"
        b << x
        p << "goto next page"

header1= html . body

With this code, every page has the menu on the top (letters or numbers). At any page the user can change from letters to numbers by clicking the menu.


Friday, July 26, 2013

Maxwell Smart push counter

To illustrate the push functionality the previous example is confusing since it seems to be a request response interaction with a web browser, but it is not, since the text box send to the server a string, it is stored in a variable, the push widget detect the update of the variable and send it back in a separate message, different that the reception message. In fact various unrelated push widgets can be updated using this asynchronous mechanism   simultaneously in the same page.

So I created another push example theoretically more simple.

http://mflowdemo.herokuapp.com/noscript/pushdec

It is a countdown after which the page will navigate back to the main menu. In this case the widget generates its own output by decreasing the variable. It also illustrates the use of Hamlet.

Note that

 - push has a new parameter that is the delay for a new ajax request when the previous connection has been lost.

- The last push after 0, send a script that forces a navigation to the menu. And then kill itself.

pushDecrease= do
 tv ←  liftIO $ newTVarIO 10
 page $ 
  [shamlet|
   <div>
       <h2> Maxwell Smart push counter
       <p> This example shows a reverse counter
       <p> To avoid unnecessary load, the push process will be killed when reaching 0
       <p> The last push message will be an script that will redirect to the menu"
       <h3> This message will be autodestroyed within ‥

  |] ++>  counter tv <++  b << "seconds" 
 where

 counter tv = push Html 0 $ do
      setTimeouts 100 0     -- kill  the thread if the user navigate away
      n ←  atomic $ readTVar tv
      if (n≡ -1) 
        then  do
          script << "window.location='/'" ++> noWidget
          liftIO $ myThreadId ↠ killThread 
        else do
          atomic $ writeTVar tv $ n - 1
          liftIO $ threadDelay 1000000
          h1 << (show n) ++> noWidget

atomic= liftIO . atomically

.....

Ops.. No.

killThread is never called since noWidget return an invalid formlet value, so the next statements are not executed in the View monad (See: The promising land of monadic formlets). 

That kill is in order to drop the process immediately, but otherwise, the timeout of setTimeouts would do the same job. Since the delay between push sends is one second, by shortening the timeout from 100 to two seconds will do the same job.  So the killthread line can be eliminated.


Wednesday, July 24, 2013

New push mode, to present data in real time. in MFlow

Another milestone completed in MFlow.  The new asynchronous widgets can display server information at the moment that they appear. And thanks to Software Transactional Memory this may be immediately.

The new primitive, push, like autoRefresh,  is a modifier of a widget behavior. In this case push  will execute the widget and present the output again and again using ajax internally. This is an example:

http://mflowdemo.herokuapp.com/noscript/push


 
 
The image is not very exciting. I will try to add another better. In this example the push widget is above the text box.
 
The code is as follows:
 
pushSample=  do
  tv ←  liftIO $ newTVarIO $ Just "The content will be appended here"
  page $   h2 << "Push example"
       ++> p << "The content of the text box will be appended to the push widget below."
       ++> p << "A push widget can have links and form fields."
       ++> p << "Since they are asynchronous the communucation must be trough..."
       ++> p << "The input box is configured with autoRefresh"
       ++> hr

       ++> pageFlow "push" (push Append (disp tv) <** input tv)
       **> br
       ++> br
       ++> wlink () << b << "exit"

  where
  -- the widget being pushed:
  disp tv= do
      setTimeouts 100 0
      line ←  tget tv
      liftIO $ when (line ≡ "kill") $ myThreadId ↠ killThread
      p <<  line ++> noWidget

  -- The input box
  input tv= autoRefresh $ do
      line ←  getString Nothing <** submitButton "Enter"
      tput tv line


  tput tv x = atomic $ writeTVar  tv ( Just x)

  tget tv= atomic $ do
      mr ←  readTVar tv
      case mr of
         Nothing → retry
         Just r → do
          writeTVar tv Nothing
          return r

atomic= liftIO . atomically

There are still some minor issues with this widget, but I expect to fix them soon. As you can see, the push widget retry when Nothing is available in the TVar. When the input widget tput's something in the variable, it is read, emptied and returned to be displayed. The other widgets of the  page must be configured with autorefresh, unless we want to navigate away from the page. This is why the text input box and the button are under autoRefresh, but the exit link is not.

Tuesday, July 16, 2013

Automatic error trace generation in MFlow

To have  the trace of an unexpected error is very important in Web development. Specially when the error has been produced in exploitation. There is no way to make tests in a exploitation environment, so the error message is the only information available to fix it as soon as possible.

Now MFlow permits the creation of execution traces. Not just call traces, but execution traces, whenever an error happens. It uses the package monadloc from Pepe Iborra, used to produce stack traces in his package control-monad-exception

Using MonadLoc, MFlow can produce entire traces instead of call stacks because his backtracking mechanism permits to  run back the execution up to the beginning in case of an exception following the exact execution steps in reverse order. In this back-execution is when the trace is generated. When running normally, the tracing machinery does not affect the performance.

This is an example of what it is necessary in order to have execution traces in case of error.  It is necessary to install the monadloc-pp and monadloc packages that install the monadloc preprocessor and the monadloc class respectively. There are two according changes in the user programs, the preprocessor directive and to include  the Control.Monad.Loc module (in big letters):



This program has an intended error at line 33

  1. {-# OPTIONS -F -pgmF MonadLoc #-}
  2. module TestREST where
  3. import MFlow.Wai.Blaze.Html.All
  4. import Data.Monoid
  5. import Data.String
  6. import Control.Monad.Loc
  7.  
  8.  
  9.  
  10.  
  11. main= runNavigation "" $ transientNav testREST
  12.  
  13.  
  14. testREST= do
  15.   setTimeouts 120 0
  16.   liftIO $ print "start/restart"
  17.  
  18.   setHeader header1
  19.  
  20.   option ←  page $   wlink "a" << p << "letters " <++ p << "or"
  21.                  <|> wlink "1" << p << "numbers"
  22.  
  23.   case option of
  24.     "1"do
  25.           page $ wlink "2" << cont "1"
  26.           page $ wlink "3" << cont "2"
  27.           page $ wlink "4" << cont "3"
  28.           page $ wlink ()  <<  "menu"
  29.  
  30.     "a"do
  31.           page $ wlink "b" << cont "a"
  32.           page $ wlink "c" << cont "b"
  33.           page $ undefined -- wlink "d" << cont "c"
  34.           page $ wlink ()  <<  "menu"
  35.  
  36.  
  37. cont x= p << "page for"
  38.         <> b << x
  39.         <> p << "goto next page"


If we navigate to execute this line with the web browser, the error produced in the console, in the file "errlog" (and in the Web browser if you are logged as administrator) is:

---------------------ERROR-------------------------
TIME=Tue Jul 16 11:52:16 Hora de verano romance 2013

TRACE (error in the last line):

testREST, TestREST(Demos\TestREST.hs): (14, 11)
testREST, TestREST(Demos\TestREST.hs): (20, 3)
testREST, TestREST(Demos\TestREST.hs): (23, 3)
testREST, TestREST(Demos\TestREST.hs): (30, 12)
testREST, TestREST(Demos\TestREST.hs): (31, 11)
testREST, TestREST(Demos\TestREST.hs): (32, 11)
testREST, TestREST(Demos\TestREST.hs): (33, 11)
exception: Prelude.undefined

USER= admin

VERB= navigation

REQUEST:
[("cookieuser","admin"),("flow","1373963274"),("Host","localhost"),("Connection","keep-alive"),("Cache-Control","max-age=0"),("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"),("User-Agent","Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.72 Safari/537.36"),("Accept-Encoding","gzip,deflate,sdch"),("Accept-Language","es-ES,es;q=0.8,en-US;q=0.6"),("Cookie","flow=1373963274; cookieuser=admin")]
 
 
Fine, Isn´t? Note that it is not a call stack, but a true execution trace.
 
If we comment out both lines the error produced is:
 
---------------------ERROR-------------------------
TIME=Tue Jul 16 12:57:04 Hora de verano romance 2013


Prelude.undefined

USER= admin

VERB= navigation

REQUEST:
...
 


How I did that?

Essentially the monadLoc instance permits to add information to a monad about the line number that it is executing now.  I attach in this instance an exception handler to each bind operation so that when a noncaugh exception reaches the handler, it add this line number to  mfTrace, a list of  strings within the internal state monad. Then it trigger a failure that initiates the backtracking (see fail back monad) each step back detect the exception condition because mfTrace is not empty. then each of these steps add its own line to the mfTrace until the execution goes back to the init, were instead of restarting the execution forward, generate a error exception with all the content of mfTrace.

This is the instance:
instance  MonadLoc (FlowM v IO) where
    withLoc loc f = FlowM . BackT $ do
       withLoc loc $ do
            s ←  get
            (r,s') ←  lift $ do
                       (r,s') ←  runWithState f s  `CE.catch` (handler1  loc s)

                       case mfTrace s' of
                            Nothing     →  return (r,s')
                            Just  trace →  return(r, s'{mfTrace= Just( loc:trace)})
            put s'
            return r
       where

       handler1 loc s (e ∷  SomeException)=
        return (GoBack, s{mfTrace= Just ["exception: " ⊕show e]}) 



This is for the MFlow monad. For the View monad, used for in-page flows, the validation fails and mfTrace is filled with the error line, which trigger the backtracking in the MFlow monad.

The code of that last version with traces is not yet in Hackage. In github is at:

 
The fail-back monad is evolving to a supervisor monad that can execute tests, produce error traces , manage exceptional conditions, undo transactions and so on. I have to abstract out this monad from MFlow and make it available as a separate package.

In the next post I promise to talk about it.

I need people interested in MFlow to collaborate !!!!

Thursday, July 11, 2013

The Web Navigation Monad

The MFlow app server can express routes within normal Haskell monadic code. The FlowM monad backtrack and goes forward to track the URL of any page within the monadic flow.

To make a web application program more close to a plain console application, I created runNavigation, that get the port from the first execution parameter. If not, it read it from the PORT environment variable. If it does not exist, it uses the por 80.

runNavigation executes a persistent navigation (whose state is logged and later recovered when the process has a timeout).  If the flow is not persistent, it must be prefixed with transientNav.

The result is a more close visualization of what the FlowM monad is: a navigation monad.

This example has two routes (letters and numbers). Each one has a simple sucession of pages. The user can navigate forward and backward, introduce any url and the program will track the proper page to respond.

I installed it on Heroku:

http://mflowdemo.herokuapp.com/noscript/restnav

This page for example, points to the second page of the numbers:

http://mflowdemo.herokuapp.com/noscript/restnav/1/2

Notice the restful URLs generated, that can be entered in the address box at any time.

When the flow finish, it goes to the beginning again.

From numbers it is possible to have a link to any letter by means of a HTML link, instead of a wlink. (wlinks return results to the flow where they are in)


main= runNavigation "" $ transientNav $ do

  liftIO $ print "start/restart"

  setHeader $ html . body

  option <- ask  $   wlink "a"  << p << "letters"
                 <|> wlink "1" << p << "numbers"

  case option of
    "1" -> do
          page $ wlink "2" << pagefor "1"
          page $ wlink "3" << pagefor "2"
          page $ wlink "4" << pagefor "3"
          page $ wlink ()  <<  "menu"
    "a" -> do
          page $ wlink "b" << pagefor "a"
          page $ wlink "c" << pagefor "b"
          page $ wlink "d" << pagefor "c"
          page $ wlink ()  <<  "menu"

pagefor x= p << "page for"
        <> b << x
        <> p << "goto next page"



page is a synonym of ask

It is a navigation of 9 pages within the main procedure. The application is stateless, since the GET URLs have ever the same response. There is no state. It is, simply, a navigation.




Wednesday, June 26, 2013

And finally... Widget auto refreshing

In the previous post I said:

Dinamic formlets are composable in MFlow ... But the entire page must be refreshed to achieve dynamic behavior. The next step is to try to avoid the need to refreshing the entire page by using ajax to refresh just the widget that has changed. ...


Now I did it with

autoRefresh :: View format monad result -> View format monad result

autoRefresh capture the form submissions and the links of the enclosed widget and send them via AJAX. The response is the new presentation of the widget, that is updated. No navigation occur. So a widget with autoRefresh can be used in heavyweight pages. If AJAX or javascript is not available, the widget is refreshed normally, via a new page.


This example, from https://github.com/agocorona/MFlow/blob/head/Demos/demos.blaze.hs :

combination = ask $
     p << "Login widget (use admin/admin)" ++> autoRefresh(pageFlow "r" wlogin)  <++ hr
     **> p << "Counter widget" ++> autoRefresh (pageFlow "c" (counterWidget 0))  <++ hr
     **> p << "Dynamic form widget" ++> autoRefresh(pageFlow "f" formWidget) <++ hr
     **> wlink () << b << "exit"


Has three active widgets (monadic formlets) with autoRefresh : A login widget, a counter and the dynamic form. They are examples  defined in the previous posts. Each of these widgets express his own flow within the page.

Thursday, June 20, 2013

The promising land of monadic formlets. Or: "Look ma! no JavaScript!"



Formlets are about applicative instances, but what about monadic instances? What a Monad instance of formlets means? I recently experimented with this and the results are very interesting -and powerful-. It mixes the best of web forms, with the flexibility of console applications.

???!!!!!!

What I mean with that? There are two fundamental questions for usability and high level programming of user interfaces.  Here are with my responses:

  1. What is the best interface? A dynamic, window-oriented or document oriented interface for some applications  and optional console-style presentation and interaction for others
  2. What is the most intuitive way of programming interfaces? The sequential style of console applications.

What if I say that monadic formlets have the potential to realize the two (or three) whishes with no compromises?
 
Let´s look at an example. There is a video of the execution below. Although this example is for the formlets of the MFlow framework , it can be ported to other formlet implementations. The MFLow formlets includes operators for web formatting that is not supported in other formlets implementations. Static HTML templating don´t work well with monadic formlets, so it is important to include the formatting as a part of the computation:

formWidget= wform $ do
      (n,s) <- (,) <$> p << "Who are you?"
                   ++> getString Nothing  <! hint "name"     <++ br
                   <*> getString Nothing  <! hint "surname"  <++ br
                   <** submitButton "ok" <++ br
                   
      flag <- b << "Do you " ++> getRadio[radiob "work?",radiob "study?"] <++ br
      
      r<-case flag of
         "work?" -> pageFlow "l"
                     $ Left  <$> b << "do you enjoy your work? "
                             ++> getBool True "yes" "no" 
                             <** submitButton "ok"  <++ br
                             
         "study?"-> pageFlow "r"
                     $ Right <$> b << "do you study in "
                             ++> getRadio[radiob "University"
                                         ,radiob "High School"]
      u <-  getCurrentUser                                     
      p << ("You are "++n++" "++s) ++>
       p << ("And your user is: "++ u) ++>
       case r of
         Left fl ->   p << ("You work and it is " ++ show fl ++ " that you enjoy your work")
                        ++> noWidget

         Right stu -> p << ("You study at the " ++ stu)
                        ++> noWidget


hint s= [("placeholder",s)]
onClickSubmit= [("onclick","this.form.submit()")]
radiob s n= text s ++&gt setRadio s n <! onClickSubmit


 
 Here wform, getBool, getString , getRadio etc are formlet elements


The first sentence is an applicative composition that generate a 2 tuple, to show that applicative and monadic can be mixed.  The operations ++> add html to the formlet. The operatior <! add attributes to the formlet element.. noWidget is a dumb formlet that does not validate.

The second monadic statement is an election between two options. The beauty of the monadic instance is that the rest of the form can vary depending on the previous answers. Since the formlets validate the input, unless the election is made, the radio will not validate, so the monadic execution will be aborted beyond any unanswered question, so nothing will appear after the question. The rest of the form will appear when the user choose one of the two options. once one or the other option is chosen, then another binary question is presented. (either he likes his work or where he study). When the questions are finised, the results are presented. This kind of presentation is similar to what we would see in a console application.

I hope that you get the idea. The benefit is not only the familiar coding and presentation of a sequential console application: Since the form encloses all the fields, At any time the user can change previous inputs and the form will reflect these changes. For example if the user change from work to study (second statements) the "where do you study will appear and the work related questions and answers will disappear. That is wonderfully useful for heavily interactive applications.

There is a problem however and it is the issue of the formlet identifiers. Unlike in an applicative presentation, now the number and type of the formlets will vary, so the response to a previous form create a new kind of form with different fields. And, because the form identifiers, assigned sequentially, vary, the post response can be misinterpreted. To avoid that , the pageFlow call creates fixed sequences of identifiers for each branch of execution.

I will release a version of MFlow that support this kind of monadic composition of fomlets, but In essence it is nothing but a Monad instance for formlets. A single server procedure, that executes the formlet code can support all the interaction so any framework can do it. The usability of that is huge: It is possible to interact in a web page in a console style with questions and answers with the versatitly of a dynamic foms: Any modification in the form change the subsequent flow of interaction. Another application of this monadic style is to ease multistep processes such are registration, check-out and payment ad so on. Even a entire interactive dynamic application can be coded in a single page.

And no javascript is needed!.

This page flow is simple, but imagine a flow where the first line includes formlets for tabs or menus An entire application can be controlled in this way.


To run this formlet in MFlow:

main=do

  addMessageFlows
       [(""    , transient $ runFlow  $ ask dynamicForm )]

  wait $ run port waiMessageFlow

 
This video show how the presentation of this example vary with the user input:



 This other video has a better resolution:
 


I hope that you find the idea interesting. If you want to experiment with this in MFlow, I have to say that the implementation of this feature is in an early stage. The code is in the head branch
 

 
The code of the example, that was executed in the video, is part of a demo:
https://github.com/agocorona/MFlow/blob/head/Demos/demos.blaze.hs

The next step: Selective refreshing.

Dinamic formlets are composable in MFlow . The video shows a counter, a login widget and this formlet working in the same page (see the code of these widgets in previous posts) But the entire page must be refreshed to achieve dynamic behavior. The next step is to try to avoid the need to refreshing the entire page by using ajax to refresh just the widget that has changed. This is halfway done now, since this functionality is available for some particular widgets. it is a matter of generalizing the mechanism.

Tuesday, June 18, 2013

Caching Web pages with TCache. Translation of a java example that uses JCache

I just read this introduction to JCache because I was curious about the similarities with my package TCache. While JCache is an standard interface for distributed HashMaps, like memcached or Resin, TCache is an implementation of a transactional cache that is not yet distributed -but I plan it to be.

But the latter has a richer semantic, since It has not only search by key, but also support the STM semantic of updates and retrievals. It also has a query language using Haskell field names and various kinds of indexations (and it is more type safe).

Java is extraordinarily verbose, and the Java people enjoy adding even more verbosity to their frameworks and standards (except perhaps the engineers at Google). 

I translated the same example in the refered article to TCache and MFlow. I will use seconds instead of milliseconds


module Main where

import MFlow.Wai.Blaze.Html.All
import Data.TCache.Memoization
import System.Time
import Control.Concurrent  -- for the console example


seconds :: IO String
seconds= do
         TOD t _ <- liftIO getClockTime
         return $ show t


-- generates the page in Text.Blaze.Html format
page :: IO Html
page= do
   t <-  seconds 
   return $ p << ("Hello World " ++ t)

-- caches the Html code
cachedPage:: IO Html
cachedPage = cachedByKey "hello message" 10 page


helloServlet=  do
      msg <- liftIO $  cachedPage
      msg ++>  noWidget


That's all the code of the Java example. cachedByKey stores the value of the computation in the cache for ten second with the key "hello message".  When the value is requested after ten seconds, the computation is re-executed again.

The operator << is a convenience operator defined in MFlow to avoid the overloaded strings extension, but what is cached in cachedPage is pure blaze-html markup. So cachedByKey can be used in any other Haskell web framework to cache Html pages.


helloServlet can also be written using wcached or wfreeze, which is specific for caching MFlow widgets:

helloServlet'= wfreeze  "hello message Widget" 10 $ messageWidget 

messageWidget ::  View Html IO ()
messageWidget= liftIO page >>= \msg -> msg ++> noWidget 


noWidget is a dumb widget that has no rendering.

To execute both servlet in the port 80:

main= do

   addMessageFlows[("noscript",wstateless helloServlet)
                   ,("alternative", wstateless helloServlet')]

   wait $ run 80 waiMessageFlow

The procedure associated to "noscript" is invoked when no path is in the URL.



A similar console program, which polls the cache every second:

main= do
      msg <-  cachedByKey "hello message text" 10 messageText
      print msg
      threadDelay 1000000
      main

messageText=do
   t <- seconds 
   return $ p <<("Hello World " ++ t)

Monday, June 10, 2013

Callbacks: Dynamic Web widgets and dynamic forms without JavaScript

A callback is an action that is executed when a widget receives valid input. MFlow has 'waction's  They execute a sequence of pages when invoked. When the flow action is finished the display return to the original page, to execute further actions or to return the result of the page form. A waction takes complete control of the navigation.

But it would be nice to execute a flow in each widget in the page simultaneously. Each widget in the page can have dynamic behaviors without using JavaScript. Seaside is an incredible web framework developed in a very nice language: Smalltalk. It has such functionality.

This seaside widget counter is replicated five times in the same page:


There you can see the beautiful and short implementation and how nice Smalltalk is.

I tried hard, and finally I developed this functionality in MFlow. The same counter widget can be defined in a similarly short way in  MFlow as such:

counterWidget n= do
  (h1 << show n
   ++> wlink "i" << b << " ++ "
   <|> wlink "d" << b << " -- ")
  `wcallback` \op -> case op of
                      "i" -> counterWidget (n + 1)
                      "d" -> counterWidget (n - 1)

Unlike the Seaside one, this is a recursive definition. The look and the behavior is the same than in the case of the Seaside counter (link above).
A page with a counter can be defined as such:

conterPage= ask $ counterWidget 0

And a page with five counters separated by horizontal lines can be defined as such:

 multicounterPage= ask $ firstOf(replicate 5 counter)
  where
  counter= counterWidget 0 <++ hr

As in the case of the Seaside example, the five independent counters can be increased and decreased independently. Moreover in both cases they behave well with the back button.

wcallback replaces a widget with other widget when the first is validated (or does whatever possible in a View monad, including the return of a result). various chained callbacks can create a local flow. Actually,  wcallback is implemented as  a bind operation:

wcallback
  :: Monad m =>
     View view m a -> (a -> View view m b) -> View view m b

The seaside callbacks works in a different way. they modify the same object, that is rendered in the next continuation.

The Haskell implementation and the use of RESTful URLs recently developed  permits a pure RESTful version of the multicounter example, while in the Seaside case, the counters state in each page is stored in a continuation that is deleted after a timeout, so when you press again the same URL, the counters will appear zeroed. In the MFlow application, the GET requests created by the increment and decrement links produce URLs that are side effect free. If you bookmarck one of these URLs and send it by email, the receiver will see the same counter values when he press the link. That is very very nice for a stateful web framework.

I said that  wcallback is a bind operations, but the real bind in the View monad is defined to perform a slightly different thing. While the former substitute the widget by other when the first is validated, bind add the new widget after the original one. This permits the creation of very interesting behaviours. For example, monadic forms instead of applicative ones that present input fields incrementally. Unlike in the case of Applicative forms, different dialogs can be presented depending on the user responses.

Here below is the code of a dynamic widget that interact with the server. It perform a monadic interaction with various steps and use a callback.

It is a functional logging widget. If the user is not anonymous, it simply display that the user is logged. If the user is not logged, it display a login box to enter the user name. once the name is entered, it display a password field below the user name. If the user is validated then the user is logged, the form dissapears and display the logged user name (in the callback). If the validation is erroneous, it displays a message below:

wlogin= do
    username <- getCurrentUser
    if username /= anonymous 
     then return username
     else do
      name <- getString (Just $ "Enter username") <++ br
      pass <- getPassword <++ br
      val  <- userValidate (name,pass)
      case val of
        Just msg -> notValid msg 
        Nothing -> login name >> return name

   `wcallback`  \name -> p << ("logged as " ++ name) ++> noWidget

You can see how the widget interact nicely with the server.

You can see all of this in the following screencast. Excuse my dizziness. To my bad English -not used for quite a while- I add the tireness of many hours of programming. I recorded the video right after I solved the last great problem before making sure that all of this is possible in MFlow. Now there remain only bugs.

This version of MFlow is at the head branch:


The video will appear after Youtube end the processing: