packages feed

ideas-0.6: src/Service/Diagnose.hs

-----------------------------------------------------------------------------
-- 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)
--
-- Diagnose a term submitted by a student
--
-----------------------------------------------------------------------------
module Service.Diagnose 
   ( Diagnosis(..), RuleID, diagnose, restartIfNeeded
   ) where 

import Common.Apply
import Common.Context
import Common.Exercise
import Common.Strategy (emptyPrefix)
import Common.Transformation
import Common.Utils (safeHead)
import Data.Maybe
import Service.TypedAbstractService

----------------------------------------------------------------
-- Result types for diagnose service

type RuleID a = Rule (Context a)

data Diagnosis a
   = Buggy          (RuleID a)
   | NotEquivalent  
   | Similar        Bool (State a)
   | Expected       Bool (State a) (RuleID a)
   | Detour         Bool (State a) (RuleID a)
   | Correct        Bool (State a)

----------------------------------------------------------------
-- The diagnose service

diagnose :: State a -> a -> Diagnosis a
diagnose state new
   -- Is the submitted term equivalent?
   | not (equivalence ex (term state) new) =
        -- Is the rule used discoverable by trying all known buggy rules?
        case discovered True of
           Just r -> -- report the buggy rule
              Buggy r
           Nothing -> -- unknown mistake
              NotEquivalent
              
   -- Is the submitted term (very) similar to the previous one? 
   | similarity ex (term state) new =
        -- If yes, report this
        Similar (ready state) state
        
   -- Was the submitted term expected by the strategy?
   | isJust expected =
        -- If yes, return new state and rule
        let (r, _, ns) = fromJust expected  
        in Expected (ready ns) ns r

   -- Is the rule used discoverable by trying all known rules?
   | otherwise =
        let ns = restartIfNeeded (state { prefix=Nothing, context=inContext ex new })
        in case discovered False of
              Just r ->  -- If yes, report the found rule as a detour
                 Detour (ready ns) ns r
              Nothing -> -- If not, we give up
                 Correct (ready ns) ns
 where
   ex = exercise state
   
   expected = do
      xs <- allfirsts (restartIfNeeded state)
      let p (_, _, ns) = similarity ex new (term ns)
      safeHead (filter p xs)

   discovered searchForBuggy = safeHead
      [ r
      | r <- ruleset ex
      , isBuggyRule r == searchForBuggy
      , ca <- applyAll r (inContext ex sub1)
      -- , let s = prettyPrinter (exercise state) (fromContext a)
      --, if s=="2*x+2 == 5" then True else error s
      , a <- fromContext ca
      , similarity ex sub2 a
      ]
    where 
      mode = not searchForBuggy
      diff = difference ex mode (term state) new
      (sub1, sub2) = fromMaybe (term state, new) diff
      
----------------------------------------------------------------
-- Helpers

-- If possible (and if needed), restart the strategy
-- Make sure that the new state has a prefix
-- When resetting the prefix, also make sure that the context is refreshed
restartIfNeeded :: State a -> State a
restartIfNeeded s 
   | isNothing (prefix s) && canBeRestarted ex = 
        case fromContext (context s) of 
           Just a -> s
              { prefix  = Just (emptyPrefix (strategy ex))
              , context = inContext ex a
              } 
           Nothing -> s
   | otherwise = s
 where
   ex = exercise s