使用具有非零自然数的函数

时间:2018-05-26 18:48:48

标签: idris

我正在尝试在Idris中定义一个函数(congruentialMethod),其中包括对我的函数提供的一些参数应用模运算。模数运算要求第二个参数为非零,因此我尝试使用modNatNZ并向我的函数类型签名添加证明。但是,我觉得我的尝试非常笨重。

首先,当我定义最终成为模数函数(let m : Nat = 2147483647)的第二个arg的值时,-I必须执行一些笨重的大小写匹配以说服Idris该值大于零。如果我不这样做,那么类型检查需要永远。

其次,当我调用我的函数(congruentialMethod)时,我真的不明白为什么必须提供证据。我在功能签名中将证明指定为auto,认为Idris能够推断它。

module Random

%default total

getUnixEpoch : IO Nat
getUnixEpoch = do time <- foreign FFI_C "#(unsigned long)time(NULL)" (IO Int)
                  pure $ fromInteger $ cast time

congruentialMethod : (seed : Nat) -> (a : Nat) -> (b : Nat) -> (m : Nat) -> {auto prf : (m = Z) -> Void} -> Stream Double
congruentialMethod seed a b m {prf} =
  (cast seed) / (cast m) :: loop seed
  where
    loop : (prev : Nat) -> Stream Double
    loop prev = let n = modNatNZ (a * prev + b) m prf
                in (cast n) / (cast m) :: loop n

main : IO ()
main = do time <- getUnixEpoch
          putStrLn $ "seed: " ++ (cast time)
          let a : Nat = 16807
          let b : Nat = 0
          let m : Nat = 2147483647
          case m of
               Z => ?shouldnt_happen
               S m' => do let random_number_stream = congruentialMethod time a b (S m') {prf = SIsNotZ}
                          ?continue

我可以以某种方式避免将证据传递给我的congruentialMethod函数吗?是否有一种不那么笨重的方式来说服伊德里斯let m : Nat = 2147483647大于零(而不是使用案例匹配)

编辑:此代码的另一个问题似乎是使用Nat执行计算的速度非常慢。使用Intmod并将函数更改为partial可以快速生成数字。显然被迫将函数定义为partial很糟糕......但也许这对另一个问题来说很重要......

1 个答案:

答案 0 :(得分:3)

Idris很难推断let fileLines = unsolved.compactMap{ Int(String($0) } // fileLines = [1, 2, 3] 样张,因为它们是函数,而Idris只是不试图推断函数,因为函数非常复杂。标准库已经考虑过你的情况了。我们有Prelude.Nat.IsSucc

Not

这适用于data IsSucc : Nat -> Type where ItIsSucc : IsSucc (S n) ,但现有的auto函数与它不兼容,因此我们使用了一些粘合剂。

Nat

就是这样:

isSuccNotZero : IsSucc n -> Not (n = Z)
isSuccNotZero {n = S _} ItIsSucc Refl impossible

使用网站现在将推断congruentialMethod : (seed : Nat) -> (a : Nat) -> (b : Nat) -> (m : Nat) -> {auto prf : IsSucc m} -> Stream Double congruentialMethod seed a b m {prf} = (cast seed / cast m) :: (congruentialMethod (modNatNZ (a * seed + b) m $ isSuccNotZero prf) a b m) 。但是,如果编号很大,编译器仍然会扼杀,正如您在编辑中看到的那样。它最终会做对,但这需要一段时间。我没有解决方案。