在 haskell 中生成给定月份和年份的日历
generate calendar of a given month and year in haskell
一周以来我一直在学习haskell并且面临着不同的问题。这次我必须根据给定的月份和年份创建一个日历。我快完成了,但问题是我无法从开始的那一天开始填充日子。
我的解决方案是
getDaysInMonth year month=(nDays,sDay)
where nDays = gregorianMonthLength year month
sDay= digitToInt(last(showWeekDate (fromGregorian year month 01)))
year=2013
month=10
months=["JANUARY","FEBRUARY","MARCH","APRIL","MAY","JUNE","JULY","AUGUST","SEPTEMBER","OCTOBER","NOVEMBER","DECEMBER"]
mnth=months!!(month-1)
monthDate = getDaysInMonth year month
startAt=snd(monthDate)
totalDays = fst(monthDate)
printLine = "\n"++concat ["+---\t" | r <- [1..7]]
check x | x>totalDays=""
| x<=totalDays=show x
genDays n m="\n "++concat[check(x)++"\t|"|x<-[n..m]]
genD 6=""
genD sP=genDays ((sP-1)*7+1) (sP*7) ++genD (sP+1)
generateCalendar=printLine++"\n "++
concat [[r]++"\t|" | r <- mnth]++printLine++
"\n Sun\t|Mon\t|Tue\t|Wed\t|Thu\t|Fri\t|Sat"++printLine++
genD 1
main=do
putStrLn generateCalendar
这个程序的输出是这样的
+---+---+---+---+---+---+---
O |C |T |O |B |E |R |
+---+---+---+---+---+---+---
Sun|Mon|Tue|Wed|Thu|Fri|Sat
+---+---+---+---+---+---+---
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 | | | | |
所以问题是 10 月份应该从星期一开始。我认为解决方案的实施有点混乱,但我该如何解决这个问题?
提前致谢
解决此问题的更 "functional" 方法是:
- 创建一个包含 35 个字符串的列表,每个字符串要么是空字符串,要么是一个(字符串化的)数字。
- 将列表分成多个块,每个块包含 7 个元素(因此您得到五个块)
- 对于每个块,将元素呈现为日历中的一行。
例如,对于 2013 年 10 月,35 个字符串的列表为:
cells = [ "", "", "", "1", "2", "3", ..., "31", "", "" ]
可以使用这个辅助函数创建块:
chunksOf7 (a:b:c:d:e:f:g:rest) = [ [a,b,c,d,e,f,g] ] ++ chunksOf7 rest
chunksOf7 xs = xs
(有更好的方法来定义 chunksOf7
,但这就足够了。)
并渲染块:
renderChunk cells = (concat $ map renderCell cells) ++ "\n"
renderCell c = pad 3 c ++ "|"
pad n str = str ++ (replicate (n-(length str)) ' ')
pad n str
在字符串 str
的右边用空格填充,直到总长度为 n
。
replicate n a
创建一个值 a
重复 n
次的列表。
并将它们放在一起(一旦你有了 cells
列表):
renderCalendarBody cells = concat (map renderChunk chunks)
where chunks = chunksOf7 cells
现在,给定一年零一个月,您只需编写一个函数来定义 cells
是什么。
单元格列表将包括:
- 一些前导空字符串
- 后跟 1 到 30(或 31 或任何月份的最后一天)
- 后跟一些尾随空字符串
即:
cellsForYearAndMonth y m = (replicate n1 "")
++ [ show d | d <- [1..lastday] ]
++ (replicate n2 "")
where lastday = ...
n1 = ... number of leading empty strings ...
n2 = ... number of trailing empty strings ...
谢谢@user5402。终于我得到了工作版本
import Data.Time.Calendar
import Data.Time.Calendar.WeekDate
import Data.Char
year=2014
month=2
months=["JANUARY","FEBRUARY","MARCH","APRIL","MAY","JUNE","JULY","AUGUST","SEPTEMBER","OCTOBER","NOVEMBER","DECEMBER"]
mnth=months!!(month-1)
monthDate = getDaysInMonth year month
startAt=snd(monthDate)
totalDays = fst(monthDate)
getDaysInMonth year month=(nDays,sDay)
where nDays = gregorianMonthLength year month
sDay= digitToInt(last(showWeekDate (fromGregorian year month 01)))
cells = (replicate n1 "")
++ [ show d | d <- [1..lastday] ]
++ (replicate n2 "")
where lastday = totalDays
n1=(startAt-1)
n2=(7-(totalDays-(29-startAt)))
chunksOf7 []=[]
chunksOf7 (a:b:c:d:e:f:g:rest) = [ [a,b,c,d,e,f,g] ] ++ chunksOf7 rest
pad n str = str ++ (replicate (n-(length str)) ' ')
renderCell c = pad 3 c ++ "|"
renderChunk cells = (concat $ map renderCell cells) ++ "\n"
printLine = "\n"++concat ["+---" | r <- [1..7]]++"\n"
monthLine=concat [[r]++" |" | r <- mnth]
dayLine="Sun|Mon|Tue|Wed|Thu|Fri|Sat"
heading=concat[printLine,"Year: ",show year,printLine,monthLine,printLine,dayLine,printLine]
renderCalendarBody cells = heading++concat (map renderChunk chunks)
where chunks = chunksOf7 cells
main= do putStrLn $ renderCalendarBody cells
一周以来我一直在学习haskell并且面临着不同的问题。这次我必须根据给定的月份和年份创建一个日历。我快完成了,但问题是我无法从开始的那一天开始填充日子。
我的解决方案是
getDaysInMonth year month=(nDays,sDay)
where nDays = gregorianMonthLength year month
sDay= digitToInt(last(showWeekDate (fromGregorian year month 01)))
year=2013
month=10
months=["JANUARY","FEBRUARY","MARCH","APRIL","MAY","JUNE","JULY","AUGUST","SEPTEMBER","OCTOBER","NOVEMBER","DECEMBER"]
mnth=months!!(month-1)
monthDate = getDaysInMonth year month
startAt=snd(monthDate)
totalDays = fst(monthDate)
printLine = "\n"++concat ["+---\t" | r <- [1..7]]
check x | x>totalDays=""
| x<=totalDays=show x
genDays n m="\n "++concat[check(x)++"\t|"|x<-[n..m]]
genD 6=""
genD sP=genDays ((sP-1)*7+1) (sP*7) ++genD (sP+1)
generateCalendar=printLine++"\n "++
concat [[r]++"\t|" | r <- mnth]++printLine++
"\n Sun\t|Mon\t|Tue\t|Wed\t|Thu\t|Fri\t|Sat"++printLine++
genD 1
main=do
putStrLn generateCalendar
这个程序的输出是这样的
+---+---+---+---+---+---+---
O |C |T |O |B |E |R |
+---+---+---+---+---+---+---
Sun|Mon|Tue|Wed|Thu|Fri|Sat
+---+---+---+---+---+---+---
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 | | | | |
所以问题是 10 月份应该从星期一开始。我认为解决方案的实施有点混乱,但我该如何解决这个问题?
提前致谢
解决此问题的更 "functional" 方法是:
- 创建一个包含 35 个字符串的列表,每个字符串要么是空字符串,要么是一个(字符串化的)数字。
- 将列表分成多个块,每个块包含 7 个元素(因此您得到五个块)
- 对于每个块,将元素呈现为日历中的一行。
例如,对于 2013 年 10 月,35 个字符串的列表为:
cells = [ "", "", "", "1", "2", "3", ..., "31", "", "" ]
可以使用这个辅助函数创建块:
chunksOf7 (a:b:c:d:e:f:g:rest) = [ [a,b,c,d,e,f,g] ] ++ chunksOf7 rest
chunksOf7 xs = xs
(有更好的方法来定义 chunksOf7
,但这就足够了。)
并渲染块:
renderChunk cells = (concat $ map renderCell cells) ++ "\n"
renderCell c = pad 3 c ++ "|"
pad n str = str ++ (replicate (n-(length str)) ' ')
pad n str
在字符串 str
的右边用空格填充,直到总长度为 n
。
replicate n a
创建一个值 a
重复 n
次的列表。
并将它们放在一起(一旦你有了 cells
列表):
renderCalendarBody cells = concat (map renderChunk chunks)
where chunks = chunksOf7 cells
现在,给定一年零一个月,您只需编写一个函数来定义 cells
是什么。
单元格列表将包括:
- 一些前导空字符串
- 后跟 1 到 30(或 31 或任何月份的最后一天)
- 后跟一些尾随空字符串
即:
cellsForYearAndMonth y m = (replicate n1 "")
++ [ show d | d <- [1..lastday] ]
++ (replicate n2 "")
where lastday = ...
n1 = ... number of leading empty strings ...
n2 = ... number of trailing empty strings ...
谢谢@user5402。终于我得到了工作版本
import Data.Time.Calendar
import Data.Time.Calendar.WeekDate
import Data.Char
year=2014
month=2
months=["JANUARY","FEBRUARY","MARCH","APRIL","MAY","JUNE","JULY","AUGUST","SEPTEMBER","OCTOBER","NOVEMBER","DECEMBER"]
mnth=months!!(month-1)
monthDate = getDaysInMonth year month
startAt=snd(monthDate)
totalDays = fst(monthDate)
getDaysInMonth year month=(nDays,sDay)
where nDays = gregorianMonthLength year month
sDay= digitToInt(last(showWeekDate (fromGregorian year month 01)))
cells = (replicate n1 "")
++ [ show d | d <- [1..lastday] ]
++ (replicate n2 "")
where lastday = totalDays
n1=(startAt-1)
n2=(7-(totalDays-(29-startAt)))
chunksOf7 []=[]
chunksOf7 (a:b:c:d:e:f:g:rest) = [ [a,b,c,d,e,f,g] ] ++ chunksOf7 rest
pad n str = str ++ (replicate (n-(length str)) ' ')
renderCell c = pad 3 c ++ "|"
renderChunk cells = (concat $ map renderCell cells) ++ "\n"
printLine = "\n"++concat ["+---" | r <- [1..7]]++"\n"
monthLine=concat [[r]++" |" | r <- mnth]
dayLine="Sun|Mon|Tue|Wed|Thu|Fri|Sat"
heading=concat[printLine,"Year: ",show year,printLine,monthLine,printLine,dayLine,printLine]
renderCalendarBody cells = heading++concat (map renderChunk chunks)
where chunks = chunksOf7 cells
main= do putStrLn $ renderCalendarBody cells