How to resolve the algorithm Calendar step by step in the Haskell programming language
How to resolve the algorithm Calendar step by step in the Haskell programming language
Table of Contents
Problem Statement
Create a routine that will generate a text calendar for any year.
Test the calendar by generating a calendar for the year 1969, on a device of the time.
Choose one of the following devices:
(Ideally, the program will generate well-formatted calendars for any page width from 20 characters up.) Kudos (κῦδος) for routines that also transition from Julian to Gregorian calendar. This task is inspired by Real Programmers Don't Use PASCAL by Ed Post, Datamation, volume 29 number 7, July 1983. For further Kudos see task CALENDAR, where all code is to be in UPPERCASE. For economy of size, do not actually include Snoopy generation in either the code or the output, instead just output a place-holder.
Let's start with the solution:
Step by Step solution about How to resolve the algorithm Calendar step by step in the Haskell programming language
The code provided is a Haskell program that prints a calendar for a given year. It uses the Data.Time
, Data.Time.Calendar
, Data.Time.Calendar.WeekDate
, Data.List.Split
, and Data.List
libraries.
The code first defines the data types Day
and Month
to represent days and months, respectively. It then defines a function monthToInt
to convert a month to an integer.
The dayFromDate
function takes a year, a month, and a day and returns the day of the week for that date. It uses the toWeekDate
function from the Data.Time.Calendar.WeekDate
library to convert the date to a week date and then uses the mod
operator to find the day of the week.
The nSpaces
function takes an integer n
and returns a Text
string containing n
spaces. The space
variable is a Text
string containing a single space.
The calMarginWidth
variable is an integer that specifies the width of the margin around the calendar. The calMargin
variable is a Text
string containing the margin.
The calWidth
variable is an integer that specifies the width of the calendar.
The listMonth
function takes a year and a month and returns a list of Text
strings representing the calendar for that month. The first element of the list is the header for the month, the second element is the header for the week, and the remaining elements are the weeks of the month.
The monthHeader
variable is a Text
string containing the header for the month. It is centered within the calendar using the center
function from the Text
library.
The weekHeader
variable is a Text
string containing the header for the week. It is created by concatenating the Text
strings for each day of the week using the intercalate
function from the Text
library.
The monthLength
variable is an integer that specifies the length of the month. It is calculated using the gregorianMonthLength
function from the Data.Time.Calendar
library.
The firstDay
variable is an integer that specifies the day of the week on which the month begins. It is calculated using the dayFromDate
function.
The days
variable is a list of Text
strings representing the days of the month. It is created by replicating the nSpaces
string firstDay
times and then appending the Text
strings for each day of the month using the map
function from the Data.List
library.
The weeks
variable is a list of Text
strings representing the weeks of the month. It is created by splitting the days
list into chunks of 7 elements using the chunksOf
function from the Data.List.Split
library and then justifying each chunk to the left within the calendar using the justifyLeft
function from the Text
library.
The weeks'
variable is a list of Text
strings representing the weeks of the month with any remaining empty weeks filled with spaces. It is created by appending the nSpaces
string to the weeks
list until it has a length of 6.
The listCalendar
function takes a year and the number of columns to use and returns a list of lists of lists of Text
strings representing the calendar for that year. The first level of the list represents the months of the year, the second level represents the weeks of the month, and the third level represents the days of the week.
The calColFromCol
function takes the number of columns in the calendar and the column number and returns the calendar column for that column. It uses the divMod
function from the Prelude
library to calculate the column and row of the calendar corresponding to the column number.
The colFromCalCol
function takes the calendar column number and returns the column number in the calendar. It uses the *
and +
operators to calculate the column number.
The center
function takes a string and a width and returns a Text
string that is centered within the specified width. It uses the center
function from the Text
library.
The printCal
function takes a list of lists of lists of Text
strings and prints the calendar to the console. It uses the mapM_
function from the Control.Monad
library to print each row of the calendar.
The printCalendar
function takes a year and the number of columns to use and prints the calendar to the console. It first checks if the number of columns is less than 20. If it is, it prints an error message to the console. Otherwise, it prints the year and the calendar to the console.
Source code in the haskell programming language
import qualified Data.Text as T
import Data.Time
import Data.Time.Calendar
import Data.Time.Calendar.WeekDate
import Data.List.Split (chunksOf)
import Data.List
data Day = Su | Mo | Tu | We | Th | Fr | Sa
deriving (Show, Eq, Ord, Enum)
data Month = January | February | March
| April | May | June
| July | August | September
| October | November | December
deriving (Show, Eq, Ord, Enum)
monthToInt :: Month -> Int
monthToInt = (+ 1) . fromEnum
dayFromDate :: Integer -> Month -> Int -> Int
dayFromDate year month day = day' `mod` 7
where (_, _, day') = toWeekDate $ fromGregorian year (monthToInt month) day
nSpaces :: Int -> T.Text
nSpaces n = T.replicate n (T.pack " ")
space :: T.Text
space = nSpaces 1
calMarginWidth = 3
calMargin :: T.Text
calMargin = nSpaces calMarginWidth
calWidth = 20
listMonth :: Integer -> Month -> [T.Text]
listMonth year month = [monthHeader, weekHeader] ++ weeks'
where
monthHeader = (T.center calWidth ' ') . T.pack $ show month
weekHeader = (T.intercalate space) $ map (T.pack . show) [(Su)..]
monthLength = toInteger $
gregorianMonthLength year $
monthToInt month
firstDay = dayFromDate year month 1
days = replicate firstDay (nSpaces 2) ++
map ((T.justifyRight 2 ' ') . T.pack . show) [1..monthLength]
weeks = map (T.justifyLeft calWidth ' ') $
map (T.intercalate space) $
chunksOf 7 days
weeks' = weeks ++ replicate (6 - length weeks) (nSpaces calWidth)
listCalendar :: Integer -> Int -> [[[T.Text]]]
listCalendar year calColumns = (chunksOf calColumns) . (map (listMonth year)) $
enumFrom January
calColFromCol :: Int -> Int
calColFromCol columns = c + if r >= calWidth then 1 else 0
where (c, r) = columns `divMod` (calWidth + calMarginWidth)
colFromCalCol :: Int -> Int
colFromCalCol calCol = calCol * calWidth + ((calCol - 1) * calMarginWidth)
center :: Int -> String -> String
center i a = T.unpack . (T.center i ' ') $ T.pack a
printCal :: [[[T.Text]]] -> IO ()
printCal = mapM_ f where
f c = mapM_ (putStrLn . T.unpack) rows
where rows = map (T.intercalate calMargin) $ transpose c
printCalendar :: Integer -> Int -> IO ()
printCalendar year columns =
if columns < 20
then putStrLn $ "Cannot print less than 20 columns"
else do
putStrLn $ center columns' "[Maybe Snoopy]"
putStrLn $ center columns' $ show year
putStrLn ""
printCal $ listCalendar year calcol'
where
calcol' = calColFromCol columns
columns' = colFromCalCol calcol'
You may also check:How to resolve the algorithm Quine step by step in the Ada programming language
You may also check:How to resolve the algorithm Narcissistic decimal number step by step in the Fōrmulæ programming language
You may also check:How to resolve the algorithm Hello world/Text step by step in the ObjectIcon programming language
You may also check:How to resolve the algorithm JortSort step by step in the Ring programming language
You may also check:How to resolve the algorithm Sorting algorithms/Radix sort step by step in the Python programming language