在idris中实现BigDecimal

时间:2016-11-12 09:36:03

标签: decimal bigdecimal idris

我正在尝试在Idris中实现一个大十字形。到目前为止我有这个:

-- a big decimal has a numerator and a 10^x value
-- it has one type for zero, 
--TODO the numerator can't be zero for any other case
--TODO and it can't be divisible by 10
data BigDecimal : (num : Integer) -> (denExp : Integer) -> Type where
  Zero : BigDecimal 0 0
  BD : (n : Integer) -> (d : Integer) -> BigDecimal n d 

我想强制上面标有“TODO”的限制。但是,我只是在学习伊德里斯,所以我甚至不确定这种限制是否是个好主意。

一般情况下,我正在尝试创建一个能够使用任意精度计算多种(加密)货币的税收计算工具。我希望能够尝试使用证明器证明该程序的一些属性。

所以,我的问题是:

  • 尝试强制执行我指定的限制是否是一个好的设计决策?
  • 在Idris中可以做这种限制吗?
  • 这是Idris中BigDecimal的一个很好的实现吗?

编辑:我在考虑类似“BD:(n:整数) - >((n = 0)=无效) - >(d:整数) - > BigDecimal nd”,所以你必须传递n不为零的证明。但我真的不知道这是不是一个好主意。

编辑2:回应Cactus的评论,这会更好吗?

data BigDecimal : Type where
    Zero : BigDecimal
    BD : (n : Integer) -> (s : Integer) -> BigDecimal

1 个答案:

答案 0 :(得分:3)

你可以在构造函数类型中拼出你的不变量:

data BigDecimal: Type where
     BDZ: BigDecimal
     BD: (n : Integer) -> {auto prf: Not (n `mod` 10 = 0)} -> (mag: Integer) -> BigDecimal

在这里,prf将确保n不能被10整除(这也意味着它不会等于0),从而确保正规性:

  • 唯一的0表示是BDZ
  • n * 10 mag 的唯一代表是BD n magBD (n * 10) (mag - 1)被拒绝,因为n * 10可被10整除,并且由于 n 本身不能被10整除,BD (n / 10) (mag + 1)也无效。

编辑:事实证明,because Integer division is non-total,Idris并没有减少构造函数n `mod` 10类型中的BD,所以即便如此就像例如一样简单BD 1 3无效。

这是一个使用Nat个号码和Data.Nat.DivMod的新版本进行全面的可分性测试:

-- Local Variables:
-- idris-packages: ("contrib")
-- End:

import Data.Nat.DivMod
import Data.So

%default total

hasRemainder : DivMod n q -> Bool
hasRemainder (MkDivMod quotient remainder remainderSmall) = remainder /= 0

NotDivides : (q : Nat) -> {auto prf: So (q /= 0)} -> Nat -> Type
NotDivides Z {prf = Oh} n impossible
NotDivides (S q) n = So (hasRemainder (divMod n q))

使用此功能,我们可以使用基于Nat的{​​{1}}表示:

BigDecimal

在构造data Sign = Positive | Negative data BigNatimal: Type where BNZ: BigNatimal BN: Sign -> (n : Nat) -> {auto prf: 10 `NotDivides` n} -> (mag: Integer) -> BigNatimal 值时很容易使用;例如这是1000:

BigNatimal

编辑2 :尝试将bn : BigNatimal bn = BN Positive 1 3 转换为Nat s。它有效,但伊德里斯并没有将BigNatimal视为总数。

fromNat'