【发布时间】:2017-04-11 17:24:42
【问题描述】:
在探索 Idris 的过程中,我尝试以“惯用”的方式编写一个小型日期处理模块。这是我目前所拥有的。
首先我有一些基本类型来表示日、月和年:
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:92:11 的 addDays 中使用预期类型检查 Date.case 块的右侧时 日期
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 dependent-type idris