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