为什么Data.Time.Clock.DiffTime具有分数实例?

时间:2018-12-28 15:00:02

标签: haskell

docs for Fractional状态:

  

分数数字,支持实数除法。

     

Haskell报告未定义分数定律。但是,通常期望'(+)'和'(*)'定义分隔环并具有以下属性:

     

recip给出乘法逆      x * recip x = recip x * x = fromInteger 1

但是Data.Time.Clock.DiffTime似乎被实现为皮秒数:

> import Data.Time
>((picosecondsToDiffTime 10) / 3) * 3 -- real division ?
0.000000000009s
>>recip 3 * (3 :: DiffTime) -- customarily expected to be 1
0.999999999999s

这是被广泛接受还是应该报告?

更新

经过一番讨论,很明显该问题应该是两个问题:

  1. 为什么大多数Fractional实例都不符合预期的法律? (文档建议小数保留为与Ratio同构的类型)
  2. 为什么Haskell会使用相同的类型来表示与时间相关的各种数量(时间点,持续时间,比率),而这些实例对大多数实例却没有意义? (如@leftaroundabout所指出)

1 个答案:

答案 0 :(得分:3)

DiffTime甚至是Num的一个实例并没有任何意义,因为从物理上讲,如果乘以两次,您将没有时间(而是平方时间) –很少讨论这种方法,但是在某些物理计算中确实会出现这种情况。

确实有意义的是彼此之间希望分时,这显然是添加Fractional实例的原因。同样,结果不是时间,而是一个实数。您可以通过其他实数缩放时间。有一个类以数学/物理上完全干净的方式表达了这一点,尽管不幸的是,它不在基本包中:VectorSpace。该实例应该是这样的:

instance VectorSpace DiffTime where
  type Scalar DiffTime = Double
  a *^ t = picosecondsToDiffTime . round
            $ a * fromIntegral (diffTimeToPicoseconds t)

在这里,将时间乘以3:三次是您的意思。您还可以使用^/(只是乘以一个倒数),然后将时间除以一个数字。

您仍然无法使用VectorSpace将时间除以以获得比率;我的free-vector-spaces软件包中的OneDimensionalDivisibleSpace.C from numeric-prelude支持此功能。两者都没有被广泛使用。

不幸的是,time库倾向于提供更多易于出错的NumFractional实例,它们只是假设一秒钟 -基本时间单位。很奇怪。 thyme library,通常在类型安全方面经过深入思考,确实实现了向量空间实例。 (不幸的是,它似乎并没有得到太多维护,但我仍然会使用它。)