packages feed

ideas-1.0: src/Service/Evaluator.hs

{-# LANGUAGE GADTs, Rank2Types #-}
-----------------------------------------------------------------------------
-- Copyright 2011, 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.Evaluator where

import Common.Library
import Control.Monad
import Service.DomainReasoner
import Service.Types
import System.Random

evalService :: Evaluator inp out a -> Service -> inp -> DomainReasoner out
evalService f = eval f . serviceFunction

data Evaluator inp out a = Evaluator
   { encoder :: Encoder out a
   , decoder :: Decoder inp a
   }

data Encoder s a = Encoder
   { encodeType    :: forall t . Type a t -> t -> DomainReasoner s
   , encodeCtxTerm :: Context a -> DomainReasoner s
   , encodeTerm    :: a -> DomainReasoner s
   , encodeTuple   :: [s] -> s
   }

data Decoder s a = Decoder
   { decodeType      :: forall t . Type a t -> s -> DomainReasoner (t, s)
   , decodeTerm      :: s -> DomainReasoner a
   , decoderExercise :: Exercise a
   }

eval :: Evaluator inp out a -> TypedValue a -> inp -> DomainReasoner out
eval f (tv ::: tp) s =
   case tp of
      t1 :-> t2 -> do
         (a, s1) <- decodeType (decoder f) t1 s
         eval f (tv a ::: t2) s1
      _ ->
         encodeType (encoder f) tp tv

decodeDefault :: Decoder s a -> Type a t -> s -> DomainReasoner (t, s)
decodeDefault dec tp s =
   case tp of
      Iso p t  -> liftM (from (first p)) (decodeType dec t s)
      Pair t1 t2 -> do
         (a, s1) <- decodeType dec t1 s
         (b, s2) <- decodeType dec t2 s1
         return ((a, b), s2)
      t1 :|: t2 ->
         liftM (first Left)  (decodeType dec t1 s) `mplus`
         liftM (first Right) (decodeType dec t2 s)
      Unit ->
         return ((), s)
      Tag _ t1 ->
         decodeType dec t1 s
      Exercise ->
         return (decoderExercise dec, s)
      StdGen -> do
         stdgen <- liftIO newStdGen
         return (stdgen, s)
      Script -> do
         script <- defaultScript (getId (decoderExercise dec))
         return (script, s)
      _ ->
         fail $ "No support for argument type: " ++ show tp

encodeDefault :: Encoder s a -> Type a t -> t -> DomainReasoner s
encodeDefault enc tp tv =
   case tp of
      Iso p t    -> encodeType enc t (to p tv)
      Pair t1 t2 ->
         case tv of
            (a, b) -> do
               x <- encodeType enc t1 a
               y <- encodeType enc t2 b
               return (encodeTuple enc [x, y])
      List t        -> liftM (encodeTuple enc) (mapM (encodeType enc t) tv)
      t1 :|: t2     -> case tv of
                          Left  a -> encodeType enc t1 a
                          Right b -> encodeType enc t2 b
      Unit          -> return (encodeTuple enc [])
      Tag _ t1      -> encodeType enc t1 tv
      Rule          -> encodeType enc String (showId tv)
      Term          -> encodeTerm enc tv
      Context       -> fromContext tv >>= encodeType enc Term
      Location      -> encodeAsString enc tv
      Id            -> encodeAsString enc tv
      Int           -> encodeAsString enc tv
      Exercise      -> return (encodeTuple enc [])
      IO t          -> do a <- liftIO tv
                          encodeType enc t a
      Exception     -> fail tv
      _             -> fail ("No support for result type: " ++ show tp)

encodeAsString :: Show b => Encoder s a -> b -> DomainReasoner s
encodeAsString enc a = encodeType enc String (show a)