-
Notifications
You must be signed in to change notification settings - Fork 36
/
Trans.hs
99 lines (73 loc) · 2.9 KB
/
Trans.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE FlexibleContexts #-}
import Control.Monad.Reader
import Control.Monad.State
import Data.List (sortBy)
import Data.Ord (comparing)
{- Список дел из TODO-списка:
* Есть список дел, которые надо сделать
Элемент списка: название и через сколько дней дедлайн
* Мы хотим считать из консоли число n: сколько дел мы можем выполнить
* И вывести в консоль сколько дней у нас есть до последнего дедлайна
* Сделать первое дело
-}
data TodoItem = TodoItem
{ todoTitle :: String
, todoDeadline :: Int } -- сколько дней осталось до дедлайна
deriving (Show)
data DoneItem = DoneItem
{ doneTodoItem :: TodoItem
, spentDays :: Int }
deriving (Show)
{- Эффекты:
1. Неизменяемый контекст: Список TodoItem
ReaderT [TodoItem] m a
2. Реальный мир (консоль)
IO a
3. Список сделанных дел
StateT [DoneItem] m a
[ Needs [TodoItem], Updates [DoneItem], CONSOLE ]
-}
lowestTodos :: Int -> [TodoItem] -> [TodoItem]
lowestTodos n = take n . sortBy (comparing todoDeadline)
lastDeadline :: [TodoItem] -> Maybe Int
lastDeadline [] = Nothing
lastDeadline l = Just $ maximum $ map todoDeadline l
topUrgent :: MonadReader [TodoItem] m
=> Int
-> m (Maybe Int)
topUrgent n = asks (lastDeadline . lowestTodos n)
doMostUrgent :: ( MonadReader [TodoItem] m
, MonadState [DoneItem] m
)
=> m ()
doMostUrgent = do
mostUrgentTask <- asks (head . lowestTodos 1)
modify (DoneItem mostUrgentTask 1:)
read'n'PrintNumber :: ( MonadReader [TodoItem] m
, MonadState [DoneItem] m
, MonadIO m
)
=> m ()
read'n'PrintNumber = do
n <- liftIO readLn
maybeDeadline <- topUrgent n
case maybeDeadline of
Nothing -> liftIO $ putStrLn "No tasks to do :("
Just d -> do
liftIO $ putStrLn $ "Max deadline after: " ++ show d
doMostUrgent
done <- get
liftIO $ print done
newtype TodoCtx m a = TodoCtx
{ runTodoCtx :: ReaderT [TodoItem] (StateT [DoneItem] m) a }
deriving (Functor, Applicative, Monad, MonadIO,
MonadReader [TodoItem], MonadState [DoneItem])
instance MonadTrans TodoCtx where
lift = TodoCtx . lift . lift
doTodo :: Monad m => [TodoItem] -> TodoCtx m a -> m a
doTodo items ctx = evalStateT (runReaderT (runTodoCtx ctx) items) []
main :: IO ()
main = do
let todos = [TodoItem "First" 3, TodoItem "Snd" 2, TodoItem "A" 5]
doTodo todos read'n'PrintNumber