考虑一个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的日期和时间lib太复杂了,java.util.Date太坏了).在我目前的玩具实现中,所有的字段都是强制性的,但是当然,将用户免于不必要的精确度(并且原始实现具有可选字段)是很好的.
所以主要目标是:
>安全:必须不惜一切代价避免非法国家
>方便:应该很容易使用类型,例如模式匹配会很酷,日历计算应该很容易…
不是很重要:
>性能:当然,使用类型不应该太慢,但是对于典型的使用,它不必在最后一个时钟周期内
>内存:如果真的很重要,那么很容易得出一个更紧凑的存储格式
> terse实现:这是一个图书馆,我愿意添加所有的代码,使事情顺利
也就是说,这一切都是暂时性的,不应该太严重.
(这不是答案,但是评论太长了,这里会更清楚)
还有另一种方法可以处理它:有一个DateTime类型,总是存储所有字段以及表示精度的参数,例如.
data Precision = Days | Seconds | Milliseconds | Nanoseconds deriving (Ord,Eq {- etc -}) data DateTime = DateTime { prec :: Precision,days :: Int,sec :: Int,ms :: Int,ns :: Int }
并使用将未使用的参数设置为0的智能构造函数.如果您有dateDifference或任何内容,则可以传播精度(Ord实例将使其整齐).
(我几乎不知道这是多么好/ Haskell-y,但其他的解决方案看起来相当凌乱,也许这更加优雅.)