【題目】有一類這樣的問題,形如:
2023年1月21日 到 2023年5月4日, 一共經過了多少天?
2023年6月6日後的1000天是什麼日期?
2023年4月1日是星期幾?
從建國到 2023年10月1日,有多少個國慶節是星期日?
…不管你使用什麼語言,請不要呼叫任何關於日期的現成api,而是自己編碼解決上述問題。
實際上,就算允許你呼叫日期-時間的api,這類問題往往也很棘手。因為歷史的原因,人類風俗習慣甚至宗教等原因,時間-日期問題總是被搞得很複雜。什麼閏年、閏月、國際日變更、時區、夏令時。。。。等等一堆概念,都反映在api中,讓人頭大。
不過,如果僅為了完成上面說的任務,大可不必殺雞用牛刀。自已寫個也很容易。
可能只需要乙個小竅門:求 a, b 日期差,只需要分別求出 a, b 到公元1年1月1日
的日期差就可以了。而這比直接求 a b 的差要更容易。
上個 haskell 碼,求日期差。
b閏年 :: int
->
bool
b閏年 year
|year
`mod`
400==0
=true
|year
`mod`
100==0
=false
|year
`mod`4=
=0=true
| otherwise =
false
--- 求距離公元1年1月1日 過去了多少天
todays :: (
int,
int,
int)
->
inttodays (1,
1,1)
=0todays (y,1,
1)= todays (y-1,
1,1)
+if b閏年 (y-1)
then
366else
365
todays (y,m,1)
= todays (y,1,
1)+sum
(take (m-1)
[31,x,31,30
,31,30
,31,31
,30,31
,30,31
])where x =
if b閏年 y then
29else
28todays (y,m,d)
= todays (y,m,1)
+(d-
1)
這段碼應該不難理解。有了 todays 函式,求 a, b 的日期差就很容易:
todays (2011,5,4) - todays (1949,1,21)
這是一種很通用的思路。多數時間、日期系統都是這樣內部表示
的。
比如: excel,實際上它的資料只有兩種:字串或者數值。
當它儲存日期時,實際上存的是 距離 1970 年 1 月 1 日 午夜的天數。只不過它用的是浮點數。其小數部分是:該時刻在一天中的位置。
我們把 excel 的格式設定為日期並不會改變它的真值,只是改變了真值的表達形式。(這個思路對軟體設計十分重要。稱為模型+檢視)
問題雖說解決了,但不是太 haskell, 還是有點像 c 語言那樣處理的影子(我們可不是要同c語言決裂,只是為了訓練函式式地思考問題)。
現在考慮到這樣乙個問題: 究竟是什麼使得日期問題看起來這麼複雜呢?
是每個月的天數不同!而且2月份天數還不穩定!!
但是: 1 年有12個月,這個是不變的!! 年分不應該跟它們一起混,被月給帶壞了啊。
我們計畫用 haskell 構造乙個 從公元1年1月1起,每個月有多少天的無限列表。只有月,沒有年!無限列表!! 說幹就幹:
--從公元1年1月開始,逐月的天數無限表
monthdays :: [
int]
monthdays = concat [[31
,f x,31,
30,31,
30,31,
31,30,
31,30,
31]| x<-[
1..]]
where f x =
if b閏年 x then
29else
28--- 求距離公元1年1月1日 過去了多少天
todays' :: (int, int, int) -> int
todays'
(y,m,d)
= let passmon =
(y-1)*
12+(m-1)in
sum(take passmon monthdays)
+(d -1)
---上面函式的逆函式,距離公元1年1月1日的天數 轉為 日期
todate :: int
->
(int
,int
,int
)todate n =
let m = f n monthdays --- 多少個滿月
days = sum $ take m monthdays ------用掉了多少天
in(m `
div`12+
1, m `mod`12+
1, n - days +1)
where
f d mon | d < head mon =
0| otherwise =
1+ f (d - head mon)
(tail mon)
---某個日期過了 n 天後的日期
dateadd :: (
int,
int,
int)
->
int-
>
(int
,int
,int
)dateadd (y,m,d) n = todate $ todays (y,m,d)
+ n
這個新版本的 todays 用了月份天數的無限列表,舒服多了。
而且,todate 這個逆問題的解決也容易很多。
haskell 基礎題解(06)
題目 如果乙個數的所有真因子 不包含它自身的因子 之和恰等於其自身,則該數為完全數,也稱為完美數 perfect number 完全數有許多奇妙的性質。但它們很稀少,你來求前幾個吧。最小的乙個是 6,因為 6 1 2 3 這個完全數的定義已經很清楚了,如果沒有什麼妙法,就地毯式搜尋也可以。下法就是 ...
haskell 基礎題解(07)
題目 11 1 1 2 1 1 3 3 1 1 4 6 4 1 這個陣勢叫楊輝三角,國外叫帕斯卡三角。前一行的數字中,每兩個相鄰的數字相加就得到下一行的數字。左右兩邊的數永遠是 1 寫個程式,輸出前幾行的楊輝三角。import data.list intersperse yang hui int y...
haskell基礎題解(14)
題目 用自然數蛇形填充乙個 n 階的方陣。當n 5時,形如 這個問題用 haskell 解決時與 題目13 差別甚微。實際上,從函式式的思考習慣看,只要讓有些行作成後反轉一下就可以了。上 ju n f x x 0.n 1 where f row even row take n row n 1.odd...