Уважаемые, не затруднит ли кого написать консольный календарик (пользователь вводит день недели соответствующий первому числу и количество дней в месяце, программа печатает в семь столбиков числа месяца). С подобным вопросом обратилась студентка на одном форуме, но спрашивала о С++, я от нечего делать написал ей на С++, а поскольку сижу изучаю хаскель, стало интересно посмотреть, как на нём это делается.
Сам подобное написать не могу, я пока ещё в самом начале изучения и элементарное для данной задачи — как вообще хранить данные введённые пользователем, не могу найти, как сделать. -/
p.s. не студент, задание сдавать мне никуда не надо.
Здравствуйте, Аноним, Вы писали:
А>Уважаемые, не затруднит ли кого написать консольный календарик (пользователь вводит день недели соответствующий первому числу и количество дней в месяце, программа печатает в семь столбиков числа месяца).
import Text.Printf
-- Будем представлять календарь как таблицу (список списков)
-- Каждая клетка таблицы может включать дату, заголовок или быть пустой
data Cell = Day Int | Header String | Empty deriving Show
-- Формируем таблицу с календарем (отделили чистую функцию от IO)
-- Строим список, который соответствует таблице, если читать ее слева направо, сверху вниз.
-- Склеиваем: заголовки, начальные пустые клетки, даты, конечные пустые клетки
-- Разбиваем полученный список на блоки по 7 элементов. Получаем "таблицу" (список списков)
-- Например, для (calendar 15 5) функция возвращает:
-- [Header "mon",Header "tue",Header "wed",Header "thu",Header "fri",Header "sat",Header "sun"]
-- [Empty,Empty,Empty,Empty,Day 1,Day 2,Day 3]
-- [Day 4,Day 5,Day 6,Day 7,Day 8,Day 9,Day 10]
-- [Day 11,Day 12,Day 13,Day 14,Day 15,Empty,Empty]
calendar :: Int -> Int -> [[Cell]]
calendar days first = splitBy 7 $ headerLine ++ datesLines
where countStart = first-1 -- количество пустых клеток на первой неделе
countEnd = (8-days-first) `mod` 7 -- количество пустых клеток на последнкй неделе
datesLines = replicate countStart Empty ++ map Day [1..days] ++ replicate countEnd Empty
headerLine = map Header ["mon", "tue", "wed", "thu", "fri", "sat", "sun"]
-- Разбивает список xs на блоки по n элементов
splitBy :: Int -> [t] -> [[t]]
splitBy _ [] = []
splitBy n xs = start : splitBy n end
where (start, end) = splitAt n xs
-- Печатает календарь (вынесли форматирование календаря в отдельную функцию)
-- Для каждой строки вызываем showLine: преобразовываем значение клетки в строку (showElement),
-- форматируем (printf) и вставляем между ними пробелы (unwords). Получаем строку для вывода на экран.
-- Полученные строки выводим на экран (unlines превращает список строк в одну строку с символами '\n')
printCalendar :: [[Cell]] -> IO ()
printCalendar cells = putStr $ unlines $ map showLine $ cells
where showLine xs = unwords $ map (printf "%3s" . showElement) xs
showElement (Day d) = show d
showElement (Header h) = h
showElement Empty = ""
main = do
first <- do putStr "Enter start day of week (1..7): " ; readLn
days <- do putStr "Enter count days in month: " ; readLn
putStrLn ""
printCalendar $ calendar days first
Использовать на свой страх и риск!
Вот, например календарь на ноябрь 2009:
Enter start day of week (1..7): 7
Enter count days in month: 30
mon tue wed thu fri sat sun
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
А>p.s. не студент, задание сдавать мне никуда не надо.
Сеньк э лот. Отдельное спасибо за коментарии. Утолили жажду, так сказать, у меня вечно терпения не хватает линейно осваивать что-то новое, всё время тянет заглянуть вперёд. В данном случае (моего знакомства с ФЯ) постоянно охота сравнений с чем-то приземлённм и обыденным, как например с решением календаря на С++. А то в доступных примерах квик сорт, конечно, впечатляет, но...