packages feed

data-structure-inferrer-1.0: Advice.hs

-- | Module providing helpful tips about minimizing the complexity of the chosen data structure
module Advice
      ( adviceDS,
        printAdvice,
        adviceDS',
        printAdvice' ) where

import Defs.Util
import Defs.Structures

import Recommend

import Data.List

-- | Type for advice data
data Advice = Advice {
    advisedDS :: Structure,                 -- ^ Structure to be advised
    reducedOperations :: [OperationName],   -- ^ Operations on which the structure is better than the recommended one
    operations :: [OperationName]           -- ^ Original operations (we can get recommendations from them)
    } deriving Show

-- | Checks if structure @s1@ is not worse than structure @s2@ on operations @opns@
notWorse :: Structure -> Structure -> [OperationName] -> Bool
notWorse s1 s2 opns = compareDS s1 s2 opns /= LT

-- | Checks if the structure @s1@ is better than the structure @s2@ on operations @opns@
better :: Structure -> Structure -> [OperationName] -> Bool
better s1 s2 opns   | s1 == s2 = True
                    | otherwise = compareDS s1 s2 opns == GT
-- | Checks if the structure @s1@ is better than each of the structures in @ss@ on operations @opns@
betterThanEach :: Structure -> [Structure] -> [OperationName] -> Bool
betterThanEach s1 ss opns = all (\s2-> better s1 s2 opns) ss

-- | Removes already recommended data structures @recs@ from the advised structures
filterAdviceForRecommended :: [Structure] -> [Advice] -> [Advice]
filterAdviceForRecommended recs = filter (\(Advice ds _ _) -> ds `notElem` recs)

-- | Returns advice data for operations @opns@ and at most @n@ operations to forget about
adviceDS' :: Integer -> [OperationName] -> [Advice]
adviceDS' n opns = let
    recOrig = recommendAllDs opns
    opnsSeqs = sequencesOfLen opns (genericLength opns - n)
    recSeqs = concatMap (\sq -> map (\x -> Advice x sq opns) $ filter (\ds-> betterThanEach ds recOrig sq) (recommendAllDs sq)) opnsSeqs
    in filterAdviceForRecommended recOrig recSeqs

-- | Returns advice data for operations @opns@
adviceDS :: [OperationName] -> [Advice]
adviceDS = adviceDS' 1

-- | Pretty prints effects of 'adviceDS''
printAdvice' :: (String -> IO ()) -> Integer -> [OperationName] -> IO ()
printAdvice' output n opns =   do
    yellowColor
    let adv = adviceDS' n opns
    let rec = recommendAllDs opns
    if length rec == 1
        then do
            output "Currently, the recommended data structure is: "
            cyanColor
            output $ (getDSName $ head rec) ++ "\n"
            yellowColor
        else do
            output "Currently, the recommended data structures are: "
            cyanColor
            output $ (foldl (\str ds -> (str ++ ", " ++ getDSName ds)) "" rec) ++ "\n"
            yellowColor
    mapM_ (printAdviceStructure output) adv
    resetColor

-- | Prints one 'Advice' element
printAdviceStructure :: (String -> IO ()) -> Advice -> IO()
printAdviceStructure output (Advice s betterOpns opns) = do
    output  "You could use "
    greenColor
    output $ getDSName s
    yellowColor
    output ", if you removed the following operations:\n"
    redColor
    output $ concatMap (\opn -> "* " ++ show opn ++ "\n") (opns \\ betterOpns)
    resetColor

-- | Pretty prints effects of 'adviceDS'
printAdvice :: (String -> IO ()) -> [OperationName] -> IO ()
printAdvice output = printAdvice' output 1