packages feed

ideas-0.6: src/Service/TypedExample.hs

{-# OPTIONS -XGADTs #-}
-----------------------------------------------------------------------------
-- Copyright 2010, Open Universiteit Nederland. This file is distributed 
-- under the terms of the GNU General Public License. For more information, 
-- see the file "LICENSE.txt", which is included in the distribution.
-----------------------------------------------------------------------------
-- |
-- Maintainer  :  bastiaan.heeren@ou.nl
-- Stability   :  provisional
-- Portability :  portable (depends on ghc)
--
-----------------------------------------------------------------------------
module Service.TypedExample (typedExample) where

import Data.Char
import Service.DomainReasoner
import Service.ModeXML
import Service.ExercisePackage
import Service.ServiceList
import Service.Types
import Common.Exercise
import Text.XML
   
typedExample :: ExercisePackage a -> Service -> [TypedValue a] -> DomainReasoner (XML, XML, Bool)
typedExample pkg service args = do
   -- Construct a request in xml
   xmlRequest <- 
      case makeArgType args of
         Nothing -> return $  
            stdReply (serviceName service) enc (exercise pkg) (return ())
         Just (reqTuple ::: reqTp) ->
            case encodeType (encoder evaluator) reqTp reqTuple of
               Left err  -> fail err
               Right xml -> return $ 
                  stdReply (serviceName service) enc (exercise pkg) xml
   -- Construct a reply in xml
   xmlReply <- return $
      case foldl dynamicApply (serviceFunction service) args of
         reply ::: replyTp ->
            case encodeType (encoder evaluator) replyTp reply of
               Left err  -> resultError err
               Right xml -> resultOk xml
   -- Check request/reply pair
   vers <- getVersion
   xmlTest <- do
      (_, txt, _) <- processXML (show xmlRequest)
      let p   = filter (not . isSpace)
          out = showXML (if null vers then xmlReply else addVersion vers xmlReply)
      return (p txt == p out)
     `catchError` 
      const (return False)
   return (xmlRequest, xmlReply, xmlTest)
 where
   (evaluator, enc)
      | withOpenMath pkg = (openMathConverterTp pkg, "openmath")
      | otherwise        = (stringFormatConverterTp pkg, "string")

stdReply :: String -> String -> Exercise a -> XMLBuilder -> XML
stdReply s enc ex body = makeXML "request" $ do 
   "service"    .=. s
   "exerciseid" .=. show (exerciseCode ex)
   "source"     .=. "test"
   "encoding"   .=. enc
   body

makeArgType :: [TypedValue a] -> Maybe (TypedValue a)
makeArgType []   = fail "makeArgType: empty list"
makeArgType [_ ::: Exercise] = fail "makeArgType: empty list"
makeArgType [tv] = return tv
makeArgType ((a1 ::: t1) : rest) = do
   a2 ::: t2 <- makeArgType rest
   return $ (a1, a2) ::: Pair t1 t2

dynamicApply :: TypedValue a -> TypedValue a -> TypedValue a
dynamicApply fun arg =
   case (fun, arg) of
      (f ::: t1 :-> t2, a ::: t3) -> 
         case equal t3 t1 of 
            Just eq -> f (eq a) ::: t2
            Nothing -> error $ "mismatch (argument type): " ++ show t3 ++ " does not match " ++ show t1
      _ -> error "mismatch (not a function)"

equal :: Type a t1 -> Type a t2 -> Maybe (t1 -> t2)
equal t1 t2 = 
   case (t1, t2) of
      (Maybe a, Maybe b) -> fmap fmap (equal a b)
      (StrategyCfg, StrategyCfg) -> Just id
      (State, State) -> Just id
      (Location, Location) -> Just id
      (Exercise, Exercise) -> Just id
      _ -> Nothing