module CGI where import List -- knihovna funkci pro manipulaci se seznamy import Maybe -- knihovna uzitecnych funkci nad typem Maybe a data State = State Int Int String [(Int,String)] -- State p s reply vars -- p ... pocet jiz provedenych kroku -- s ... pocet kroku, ktere chceme provest -- reply ... odpoved -- vars ... seznam dvojic (cislo dotazu, odpoved) data CGI a = CGI (State -> (State, a)) instance Monad CGI where CGI f >>= g' = CGI h where h state -- jen kvuli efektivite (aby se zbytecne nezkousely provadet -- nasledujici akce): | p > s = (state', undefined) -- jinak sami o sobe nedelame nic, jen predavame stav | otherwise = g state' where (state', x) = f state State p s reply vars = state' CGI g = g' x return x = CGI (\state -> (state, x)) cgiPage :: String -> CGI String cgiPage dotaz = CGI f where f (State p s reply vars) -- pokud to neni aktualni krok, jenom vratit prislusnou hodnotu | p < s = (State (p + 1) s reply vars, fromJust $ lookup p vars) -- je-li to aktualni krok, zapiseme dotaz | p == s = (State (p + 1) s dotaz vars, undefined) -- sem bychom se nemeli dostat, viz definice >>= | otherwise = error "Chyba" runCgi :: CGI () -> String -> String -> String runCgi (CGI cgi) stav odpoved = if reply == "" then "" else "Stav: " ++ formatState next vars ++ "; " ++ reply ++ "?" where -- zavolej funkci z cgi (State next _ reply _, _) = cgi (State 0 krok "" vars) -- s hodnotami naparsovanymi ze stavu (krok, vars) = if stav == "" then (0, []) else (qn + 1, map splitVarDef vardefs ++ [(qn, odpoved)]) (q : vardefs) = splitOn ',' stav qn = read (splitOn '=' q !! 1) splitVarDef vardef = let ['o' : o, val] = splitOn '=' vardef in (read o - 1, val) splitOn x lst | zbytek == "" = [zacatek] | otherwise = zacatek : splitOn x (tail zbytek) where (zacatek, zbytek) = span (/= x) lst -- formatovani vystupu formatState next vars = "q=" ++ show (next - 1) ++ concatMap formatVar vars formatVar (n, val) = ",o" ++ show (n + 1) ++ "=" ++ val cgi :: CGI () cgi = do r1 <- cgiPage "Dotaz 1" r2 <- cgiPage "Dotaz 2" r3 <- cgiPage ("Dotaz 3 (vase predchozi odpoved byla " ++ r2) return ()