BigDecimal implementation in idris

I am trying to implement bigdecimal in Idris. I still have this:

-- 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 

I would like to introduce the restrictions indicated by "TODO" above. However, I'm just learning Idris, so I'm not even sure if this restriction is a good idea or not.

In general, I'm trying to create a tax calculation tool that can calculate several (crypto) currencies using arbitrary accuracy. I would like to try to use this method later to prove some properties of the program.

So my questions are:

  • Is it a good design decision to try to apply the limitations that I have indicated?
  • Is it possible to make such a restriction in Idris?
  • Is this a good BigDecimal implementation in Idris?

: - "BD: (n: Integer) → ((n = 0) = Void) → (d: Integer) → BigDecimal nd", n . , .

2: Cactus ?

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

:

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 mag: BD (n * 10) (mag - 1) , n * 10 10, n 10, BD (n / 10) (mag + 1) .

: , Integer , n `mod` 10 BD, - , , BD 1 3 .

, Nat ural numbers, 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))

, BigDecimal Nat:

data Sign = Positive | Negative

data BigNatimal: Type where
     BNZ: BigNatimal
     BN: Sign -> (n : Nat) -> {auto prf: 10 `NotDivides` n} -> (mag: Integer) -> BigNatimal

BigNatimal; 1000:

bn : BigNatimal
bn = BN Positive 1 3

EDIT 2: Nat BigNatimal s. , fromNat' .

tryDivide : (q : Nat) -> {auto prf : So (q /= 0)} -> (n : Nat) -> Either (q `NotDivides` n) (DPair _ (\n' => n' * q = n))
tryDivide Z {prf = Oh} n impossible
tryDivide (S q) n with (divMod n q)
  tryDivide _ (quot * (S q)) | MkDivMod quot Z _ = Right (quot ** Refl)
  tryDivide _ (S rem + quot * (S q)) | MkDivMod quot (S rem) _ = Left Oh

fromNat' : (n : Nat) -> {auto prf: So (n /= 0)} -> DPair BigNatimal NonZero
fromNat' Z {prf = Oh} impossible
fromNat' (S n) {prf = Oh} with (tryDivide 10 (S n))
  fromNat' (S n) | Left prf = (BN Positive (S n) {prf = prf} 1 ** ())
  fromNat' _ | Right (Z ** Refl) impossible
  fromNat' _ | Right ((S n') ** Refl) with (fromNat' (S n'))
    fromNat' _ | Right _ | (BNZ ** nonZero) = absurd nonZero
    fromNat' _ | Right _ | ((BN sign k {prf} mag) ** _) = (BN sign k {prf = prf} (mag + 1) ** ())

fromNat : Nat -> BigNatimal
fromNat Z = BNZ
fromNat (S n) = fst (fromNat' (S n))
+3

Source: https://habr.com/ru/post/1660565/


All Articles