我正在尝试在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”的限制。但是,我只是在学习伊德里斯,所以我甚至不确定这种限制是否是个好主意。
一般情况下,我正在尝试创建一个能够使用任意精度计算多种(加密)货币的税收计算工具。我希望能够尝试使用证明器证明该程序的一些属性。
所以,我的问题是:
编辑:我在考虑类似“BD:(n:整数) - >((n = 0)=无效) - >(d:整数) - > BigDecimal nd”,所以你必须传递n不为零的证明。但我真的不知道这是不是一个好主意。
编辑2:回应Cactus的评论,这会更好吗?
data BigDecimal : Type where
Zero : BigDecimal
BD : (n : Integer) -> (s : Integer) -> BigDecimal
答案 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),从而确保正规性:
BDZ
BD n mag
:
BD (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'