在我探索伊德里斯的旅程中,我试图用“惯用”的方式编写一个小日期处理模块。这是我到目前为止。如何在计算日期时正确处理Fin n和Integer?
首先,我有一些基本的类型来表示天,月,年:
module Date
import Data.Fin
Day : Type
Day = Fin 32
data Month : Type where
January : Month
February : Month
....
toNat : Month -> Nat
toNat January = 1
toNat February = 2
...
data Year : Type where
Y : Integer -> Year
record Date where
constructor MkDate
day : Day
month : Month
year : Year
我想实现的功能addDays
的天数部分添加到Date
。为此我定义了下面的辅助功能:
isLeapYear : Year -> Bool
isLeapYear (Y y) =
(((y `mod` 4) == 0) && ((y `mod` 100) /= 0)) || ((y `mod` 400) == 0)
daysInMonth : Month -> Year -> Day
daysInMonth January _ = 31
daysInMonth February year = if isLeapYear year then 29 else 28
daysInMonth March _ = 31
...
最后尝试定义addDays
为:
addDays : Date -> Integer -> Date
addDays (MkDate d m y) days =
let maxDays = daysInMonth m y
shiftedDays = finToInteger d + days
in case integerToFin shiftedDays (finToNat maxDays) of
Nothing => ?hole_1
Just x => MkDate x m y
我坚持的最基本的情况下增加的天数适合当前月的持续时间。下面是编译器的输出:
当Date.idr检查addDays Date.case块的右侧:92:11与期望的类型 日期
When checking argument day to constructor Date.MkDate:
Type mismatch between
Fin (finToNat maxDays) (Type of x)
and
Day (Expected type)
Specifically:
Type mismatch between
finToNat maxDays
and
32
这是令人费解因为类型的maxDays
应该明显是Day
这简直就是Fin 32
。
我怀疑这可能涉及到daysInMonth
非整体从的isLeapYear
非整体性本身来源于mod
非全部为Integer
型茎。
非常感谢您的见解,像往常一样非常有帮助!我实际上知道与日期*和*工作是非常困难和充满危险的。我受到时区问题的困扰已经足以吸取教训。我的野心比较温和,日期是由我正在研究的另一个问题引发的一个牦牛剃须练习。我的目标不是建立一个完整的日期库(尚未),只有一个可行且有趣的Date日志类型 – insitu
也要感谢链接到其他SO问题,这个问题导致我:https:// forge .ocamlcore.org/scm/viewvc.php/trunk/calendarFAQ-2.6.txt?view = markup&root = calendar绝对是一个很棒的阅读! – insitu