packages feed

ideas-1.0: src/Service/ProblemDecomposition.hs

-----------------------------------------------------------------------------
-- 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.ProblemDecomposition
   ( problemDecomposition, replyType
   ) where

import Common.Library
import Common.Utils
import Data.Maybe
import Service.State
import Service.Types

problemDecomposition :: Maybe Id -> State a -> Maybe a -> Either String (Reply a)
problemDecomposition msloc state answer
   | isNothing $ subStrategy sloc (strategy ex) =
        Left "request error: invalid location for strategy"
   | otherwise =
   let pr = fromMaybe (emptyPrefix $ strategy ex) (statePrefix state) in
         case (runPrefixLocation sloc pr requestedTerm, fmap (inContext ex) answer) of
            ([], _) -> Left "strategy error: not able to compute an expected answer"
            (answers, Just answeredTerm)
               | not (null witnesses) -> Right $
                    Ok newLocation newState
                  where
                    witnesses   = filter (similarity ex answeredTerm . fst) $ take 1 answers
                    (newCtx, newPrefix) = head witnesses
                    newLocation = nextTaskLocation (strategy ex) sloc $
                                     fromMaybe topId $ nextMajorForPrefix newPrefix newCtx
                    newState    = makeState ex (Just newPrefix) newCtx
            ((expected, pref):_, maybeAnswer) -> Right $
                    Incorrect isEquiv newLocation expState arguments
             where
               newLocation = subTaskLocation (strategy ex) sloc loc
               expState = makeState ex (Just pref) expected
               isEquiv  = maybe False (equivalence ex expected) maybeAnswer
               (loc, arguments) = fromMaybe (topId, []) $
                                     firstMajorInPrefix pr pref requestedTerm
 where
   ex    = exercise state
   topId = getId (strategy ex)
   sloc  = fromMaybe topId msloc
   requestedTerm = stateContext state

-- | Continue with a prefix until a certain strategy location is reached. At least one
-- major rule should have been executed
runPrefixLocation :: Id -> Prefix a -> a -> [(a, Prefix a)]
runPrefixLocation loc p0 =
   concatMap (checkPair . f) . derivations .
   cutOnStep (stop . lastStepInPrefix) . prefixTree p0
 where
   f d = (lastTerm d, fromMaybe p0 (lastStep d))
   stop (Just (Exit info)) = getId info == loc
   stop _ = False

   checkPair result@(a, p)
      | null rules            = [result]
      | all isMinorRule rules = runPrefixLocation loc p a
      | otherwise             = [result]
    where
      rules = stepsToRules $ drop (length $ prefixToSteps p0) $ prefixToSteps p

firstMajorInPrefix :: Prefix a -> Prefix a -> a -> Maybe (Id, ArgValues)
firstMajorInPrefix p0 p a = do
   let newSteps = drop (length $ prefixToSteps p0) (prefixToSteps p)
   is <- firstLocation newSteps
   return (is, argumentsForSteps a newSteps)
 where
   firstLocation :: HasId l => [Step l a] -> Maybe Id
   firstLocation [] = Nothing
   firstLocation (Enter info:RuleStep r:_) | isMajorRule r = Just (getId info)
   firstLocation (_:rest) = firstLocation rest

argumentsForSteps :: a -> [Step l a] -> ArgValues
argumentsForSteps a0 = flip rec a0 . stepsToRules
 where
   rec [] _ = []
   rec (r:rs) a
      | isMinorRule r  = concatMap (rec rs) (applyAll r a)
      | applicable r a = fromMaybe [] (expectedArguments r a)
      | otherwise      = []

nextMajorForPrefix :: Prefix a -> a -> Maybe Id
nextMajorForPrefix p0 a = do
   (_, p1)  <- safeHead $ runPrefixMajor p0 a
   rec (reverse (prefixToSteps p1))
 where
   rec [] = Nothing
   rec (Enter info:_) = Just (getId info)
   rec (Exit  info:_) = Just (getId info)
   rec (_:rest)       = rec rest

-- Copied from TypedAbstractService: clean me up
runPrefixMajor :: Prefix a -> a -> [(a, Prefix a)]
runPrefixMajor p0 =
   map f . derivations . cutOnStep (stop . lastStepInPrefix) . prefixTree p0
 where
   f d = (lastTerm d, fromMaybe p0 (lastStep d))
   stop (Just (RuleStep r)) = isMajorRule r
   stop _ = False

------------------------------------------------------------------------
-- Data types for replies

data Reply a = Ok Id (State a)
             | Incorrect Bool Id (State a) ArgValues

------------------------------------------------------------------------
-- Type definition

replyType :: Type a (Reply a)
replyType = Iso (f <-> g) tp
 where
   f (Left (a, b))        = Ok a b
   f (Right (a, b, c, d)) = Incorrect a b c d

   g (Ok a b)            = Left (a, b)
   g (Incorrect a b c d) = Right (a, b, c, d)

   tp  =  Tag "correct"   (tuple2 locType stateType)
      :|: Tag "incorrect" (tuple4 (Tag "equivalent" Bool) locType stateType argsType)

   locType  = Tag "location" Id
   argsType = List ArgValueTp