diff --git a/app/Main.hs b/app/Main.hs index 769bbb1..e005532 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -151,4 +151,4 @@ run elms = do main :: IO () main = do elms <- runInputT inputSettings $ run testElements - putStrLn $ show elms + putStrLn $ elementsToString elms diff --git a/src/Cards.hs b/src/Cards.hs index 6442aeb..534857d 100644 --- a/src/Cards.hs +++ b/src/Cards.hs @@ -5,6 +5,7 @@ module Cards , toDueCards , fromCards , elementsToString + , parseElements , Card -- Card stuff , sides , tier @@ -24,6 +25,11 @@ import Data.List import qualified Data.Map.Strict as Map import Data.Time +-- | Contains 'Card's and comments with a certain ordering. +-- To update some 'Card's in an 'Elements', use 'toCards' or 'toDueCards' and +-- 'fromCards'. +-- 'Card's can be removed (not added), as long as the numbers +-- associated to the remaining cards stay with their original card. data Elements = Elements (Map.Map Integer Element) deriving (Show) @@ -31,19 +37,32 @@ data Element = ECard Card | EComment String deriving (Show) +-- | A single index card with one or more sides. data Card = Card { sides :: [String] + -- ^ The sides of a 'Card'. + -- As opposed to real index cards, a 'Card' may have more or less than two + -- sides. , tier :: Tier + -- ^ The 'Tier' of a 'Card'. , lastChecked :: UTCTime + -- ^ The time a 'Card' was last looked at. , offset :: NominalDiffTime + -- ^ A random offset, used when determining whether a 'Card' needs to be + -- revised. + -- This is to "stretch out" cards revised in a short time frame. } deriving (Show) +-- | The "level" of a 'Card' in a typical index card learning scheme. +-- Represents the time which should elapse before the 'Card' is looked at again. data Tier = Unrevised | TenMin | TwentyMin | FortyMin | OneDay | TwoDays | FourDays | EightDays | SixteenDays | ThirtyTwoDays | SixtyFourDays deriving (Show, Eq, Ord, Enum, Bounded) +-- | A 'Elements' containing some cards and some comments, for testing. +-- Will be removed soon. testElements :: Elements testElements = Elements . Map.fromList. zip [1..] $ [ card ["first card", "really"] @@ -60,16 +79,26 @@ testElements = Elements . Map.fromList. zip [1..] $ - Elements stuff -} +-- | @'updateElements' a b@ adds the updated values from @b@ to @a@. updateElements :: Elements -> Elements -> Elements updateElements (Elements old) (Elements new) = Elements $ Map.union new old +-- | Extract all 'Card's from an 'Elements'. +-- Entries may be deleted or modified, as long as the numbers are not changed +-- and stay associated to their original 'Card'. toCards :: Elements -> [(Integer, Card)] toCards (Elements elms) = [(key, card) | (key, Just card) <- mapSnd toCard $ Map.toList elms] +-- | Extract all 'Card's which are due from an 'Elements'. +-- Entries may be deleted or modified, as long as the numbers are not changed +-- and stay associated to their original 'Card'. toDueCards :: UTCTime -> Elements -> [(Integer, Card)] toDueCards time = filter (isDue time . snd) . toCards +-- | Convert a list of 'Card's back into an 'Elements'. +-- As long as the same numbers are assosiated to the same cards as they were +-- originally, this can safely be used to update the original 'Elements'. fromCards :: [(Integer, Card)] -> Elements fromCards = Elements . Map.fromList . mapSnd fromCard @@ -91,6 +120,7 @@ fromCard = ECard - Card stuff -} +-- | @'isDue' time card@ returns whether @card@ needs to be revised at @time@. isDue :: UTCTime -> Card -> Bool isDue time Card{tier=t, lastChecked=lc, offset=o} = diffUTCTime time lc >= o + tierDiff t @@ -101,20 +131,25 @@ updateOffset :: Card -> IO Card updateOffset Card{sides=s, tier=t, lastChecked=lc} = do return Card{sides=s, tier=t, lastChecked=lc, offset=0} +-- | Reset a card's 'Tier'. +-- This also resets the 'lastChecked' and 'offset' times. reset :: UTCTime -> Card -> Card reset time Card{sides=s} = Card{sides=s, tier=minBound, lastChecked=time, offset=0} +-- | Push a 'Card' to the next highest 'Tier'. +-- Set the 'lastChecked' and 'offset' time accordingly. +-- Uses the IO monad to access the global random number generator. update :: UTCTime -> Card -> IO Card update time Card{sides=s, tier=t} = updateOffset $ Card {sides=s, tier=boundedSucc t, lastChecked=time, offset=0} --- helper function boundedSucc :: (Eq a, Bounded a, Enum a) => a -> a boundedSucc a | a == maxBound = a | otherwise = succ a +-- | Create a new card. createCard :: UTCTime -> [String] -> Card createCard time s = Card{sides=s, tier=minBound, lastChecked=time, offset=0} @@ -123,6 +158,7 @@ createCard time s = - Tier stuff -} +-- | The 'NominalDiffTime' associated with each 'Tier'. tierDiff :: Tier -> NominalDiffTime tierDiff Unrevised = 0 tierDiff TenMin = 60 * 10 @@ -136,6 +172,7 @@ tierDiff SixteenDays = 3600 * (16 * 24 - 8) tierDiff ThirtyTwoDays = 3600 * (32 * 24 - 8) tierDiff SixtyFourDays = 3600 * (64 * 24 - 8) +-- | The name associated with each 'Tier'. tierName :: Tier -> String tierName Unrevised = "unrevised" tierName TenMin = "10min" @@ -153,6 +190,8 @@ tierName SixtyFourDays = "64d" - Converting to String -} +-- | Convert an 'Elements' to a string which can be parsed by 'parseElements'. +-- This string can then be written to a text file for storage. elementsToString :: Elements -> String elementsToString (Elements e) = let elms = map snd $ Map.toList e @@ -168,10 +207,12 @@ cardToString Card{sides=s, tier=t, lastChecked=lc, offset=o} = ", \"last_checked\": " ++ (show $ formatTime defaultTimeLocale "%s" lc) ++ ", \"delay\": " ++ (show $ fromEnum o) ++ "}" - in unlines $ info : intersperse "::" s + in unlines $ info : intersperse "::" s ++ [""] -- newline at the end {- - Parsing -} --- TODO +-- | Not yet implemented. +parseElements :: String -> Maybe Elements +parseElements = undefined