考虑一个DateTime类型,日期必须存在,但是秒钟部分是可选的。如果时间部分存在,则可能会有一个可选的毫秒部分。如果毫秒存在,则可能会有纳秒部分。
有很多处理这种情况的方法,例如:
--rely on smart constructors
data DateTime = DateTime { days:: Int,
sec :: Maybe Int,
ms :: Maybe Int,
ns :: Maybe Int
}
-- list all possibilities
data DateTime = DateOnly Int
| DateWithSec Int Int
| DateWithMilliSec Int Int Int
| DateWithNanoSec Int Int Int Int
-- cascaded Maybe
data DateTime = DateTime Int (Maybe (Int, Maybe (Int, Maybe Int)))
-- cascaded data
data Nano = NoNano | Nano Int
data MilliSec = NoMilliSec | MilliSec Int Nano
data Sec = NoSec | Sec Int MilliSec
data Date = Date Int Sec
你会使用哪种结构(当然不仅限于上面的示例),为什么?【意图】
我正在探索在Frege中实现日期类型的可能性(http://code.google.com/p/frege/),使用date4j的
DateTime
作为指南(因为Haskell的日期和时间库太复杂了,而java.util.Date
太过混乱)。在我的目前的玩具实现中,所有字段都是必须的,但当然可以使用户摆脱不需要的精度(而原始实现中有可选字段)。所以主要目标是:
- 安全:必须尽一切可能避免非法状态
- 方便:应该很容易使用这种类型,例如模式匹配很酷,日历计算应该很容易...
- 性能:当然,与类型一起工作不应该太慢,但对于典型用途,它不必挤出最后一个时钟周期
- 内存:在真正重要的情况下,很容易导出更紧凑的存储格式
- 简洁的实现:这是一个库,我愿意添加所有必要的代码使事情变得顺畅
DateTime = DateTime [Int]
,该函数未从库中导出,并强制所有与类型的交互都通过诸如mkDateTimeWithSec :: [Int] -> DateTime
、isDateTimeWithSec :: DateTime -> Bool
、getSeconds :: DateTime -> Maybe Int
等函数进行。您不能使用模式匹配(但也许这并不可怕,因为您只需用守卫替换它并使用访问器函数),但您明确禁止用户创建非法状态,因为您可以在构造时检查所有内容(例如,您可以检查负值)。 - Chris Taylor