Add haddoc documentation to Cards.hs

This commit is contained in:
Joscha 2018-01-04 18:23:51 +00:00
parent 7eb9954a05
commit 9eddf454e3
2 changed files with 45 additions and 4 deletions

View file

@ -151,4 +151,4 @@ run elms = do
main :: IO () main :: IO ()
main = do main = do
elms <- runInputT inputSettings $ run testElements elms <- runInputT inputSettings $ run testElements
putStrLn $ show elms putStrLn $ elementsToString elms

View file

@ -5,6 +5,7 @@ module Cards
, toDueCards , toDueCards
, fromCards , fromCards
, elementsToString , elementsToString
, parseElements
, Card -- Card stuff , Card -- Card stuff
, sides , sides
, tier , tier
@ -24,6 +25,11 @@ import Data.List
import qualified Data.Map.Strict as Map import qualified Data.Map.Strict as Map
import Data.Time 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) data Elements = Elements (Map.Map Integer Element)
deriving (Show) deriving (Show)
@ -31,19 +37,32 @@ data Element = ECard Card
| EComment String | EComment String
deriving (Show) deriving (Show)
-- | A single index card with one or more sides.
data Card = Card data Card = Card
{ sides :: [String] { 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 , tier :: Tier
-- ^ The 'Tier' of a 'Card'.
, lastChecked :: UTCTime , lastChecked :: UTCTime
-- ^ The time a 'Card' was last looked at.
, offset :: NominalDiffTime , 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) } 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 data Tier = Unrevised
| TenMin | TwentyMin | FortyMin | TenMin | TwentyMin | FortyMin
| OneDay | TwoDays | FourDays | EightDays | OneDay | TwoDays | FourDays | EightDays
| SixteenDays | ThirtyTwoDays | SixtyFourDays | SixteenDays | ThirtyTwoDays | SixtyFourDays
deriving (Show, Eq, Ord, Enum, Bounded) deriving (Show, Eq, Ord, Enum, Bounded)
-- | A 'Elements' containing some cards and some comments, for testing.
-- Will be removed soon.
testElements :: Elements testElements :: Elements
testElements = Elements . Map.fromList. zip [1..] $ testElements = Elements . Map.fromList. zip [1..] $
[ card ["first card", "really"] [ card ["first card", "really"]
@ -60,16 +79,26 @@ testElements = Elements . Map.fromList. zip [1..] $
- Elements stuff - Elements stuff
-} -}
-- | @'updateElements' a b@ adds the updated values from @b@ to @a@.
updateElements :: Elements -> Elements -> Elements updateElements :: Elements -> Elements -> Elements
updateElements (Elements old) (Elements new) = Elements $ Map.union new old 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 -> [(Integer, Card)]
toCards (Elements elms) = toCards (Elements elms) =
[(key, card) | (key, Just card) <- mapSnd toCard $ Map.toList 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 :: UTCTime -> Elements -> [(Integer, Card)]
toDueCards time = filter (isDue time . snd) . toCards 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 :: [(Integer, Card)] -> Elements
fromCards = Elements . Map.fromList . mapSnd fromCard fromCards = Elements . Map.fromList . mapSnd fromCard
@ -91,6 +120,7 @@ fromCard = ECard
- Card stuff - Card stuff
-} -}
-- | @'isDue' time card@ returns whether @card@ needs to be revised at @time@.
isDue :: UTCTime -> Card -> Bool isDue :: UTCTime -> Card -> Bool
isDue time Card{tier=t, lastChecked=lc, offset=o} = isDue time Card{tier=t, lastChecked=lc, offset=o} =
diffUTCTime time lc >= o + tierDiff t diffUTCTime time lc >= o + tierDiff t
@ -101,20 +131,25 @@ updateOffset :: Card -> IO Card
updateOffset Card{sides=s, tier=t, lastChecked=lc} = do updateOffset Card{sides=s, tier=t, lastChecked=lc} = do
return Card{sides=s, tier=t, lastChecked=lc, offset=0} 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 :: UTCTime -> Card -> Card
reset time Card{sides=s} = reset time Card{sides=s} =
Card{sides=s, tier=minBound, lastChecked=time, offset=0} 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 :: UTCTime -> Card -> IO Card
update time Card{sides=s, tier=t} = update time Card{sides=s, tier=t} =
updateOffset $ Card {sides=s, tier=boundedSucc t, lastChecked=time, offset=0} updateOffset $ Card {sides=s, tier=boundedSucc t, lastChecked=time, offset=0}
-- helper function
boundedSucc :: (Eq a, Bounded a, Enum a) => a -> a boundedSucc :: (Eq a, Bounded a, Enum a) => a -> a
boundedSucc a boundedSucc a
| a == maxBound = a | a == maxBound = a
| otherwise = succ a | otherwise = succ a
-- | Create a new card.
createCard :: UTCTime -> [String] -> Card createCard :: UTCTime -> [String] -> Card
createCard time s = createCard time s =
Card{sides=s, tier=minBound, lastChecked=time, offset=0} Card{sides=s, tier=minBound, lastChecked=time, offset=0}
@ -123,6 +158,7 @@ createCard time s =
- Tier stuff - Tier stuff
-} -}
-- | The 'NominalDiffTime' associated with each 'Tier'.
tierDiff :: Tier -> NominalDiffTime tierDiff :: Tier -> NominalDiffTime
tierDiff Unrevised = 0 tierDiff Unrevised = 0
tierDiff TenMin = 60 * 10 tierDiff TenMin = 60 * 10
@ -136,6 +172,7 @@ tierDiff SixteenDays = 3600 * (16 * 24 - 8)
tierDiff ThirtyTwoDays = 3600 * (32 * 24 - 8) tierDiff ThirtyTwoDays = 3600 * (32 * 24 - 8)
tierDiff SixtyFourDays = 3600 * (64 * 24 - 8) tierDiff SixtyFourDays = 3600 * (64 * 24 - 8)
-- | The name associated with each 'Tier'.
tierName :: Tier -> String tierName :: Tier -> String
tierName Unrevised = "unrevised" tierName Unrevised = "unrevised"
tierName TenMin = "10min" tierName TenMin = "10min"
@ -153,6 +190,8 @@ tierName SixtyFourDays = "64d"
- Converting to String - 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 -> String
elementsToString (Elements e) = elementsToString (Elements e) =
let elms = map snd $ Map.toList 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) ++ ", \"last_checked\": " ++ (show $ formatTime defaultTimeLocale "%s" lc) ++
", \"delay\": " ++ (show $ fromEnum o) ++ ", \"delay\": " ++ (show $ fromEnum o) ++
"}" "}"
in unlines $ info : intersperse "::" s in unlines $ info : intersperse "::" s ++ [""] -- newline at the end
{- {-
- Parsing - Parsing
-} -}
-- TODO -- | Not yet implemented.
parseElements :: String -> Maybe Elements
parseElements = undefined