ideas-0.7: src/Service/Evaluator.hs
{-# LANGUAGE GADTs, Rank2Types #-}
-----------------------------------------------------------------------------
-- 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.Evaluator where
import Common.Library
import Control.Monad
import Data.List
import Service.ExercisePackage
import Service.Types
import Service.DomainReasoner
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
, 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
, decoderPackage :: ExercisePackage a
}
decoderExercise :: Decoder s a -> Exercise a
decoderExercise = exercise . decoderPackage
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 f _ t -> liftM (first f) (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
ExercisePkg ->
return (decoderPackage dec, 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 _ f t -> encodeType enc t (f tv)
Pair t1 t2 -> do
let (a, b) = tv
x <- encodeType enc t1 a
y <- encodeType enc t2 b
return (encodeTuple enc [x, y])
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
IO t1 -> do let pp s | "user error (" `isPrefixOf` s = init (drop 12 s)
| otherwise = s
result <- liftIO $
liftM Right tv `catch` (return . Left . pp . show)
case result of
Left msg -> fail msg
Right a -> encodeType enc t1 a
Rule -> encodeType enc String (showId tv)
Term -> encodeTerm enc tv
Context -> fromContext tv >>= encodeType enc Term
Location -> encodeType enc String (show tv)
ExercisePkg -> return (encodeTuple enc [])
_ -> fail ("No support for result type: " ++ show tp)