Я занимался созданием собственного генератора случайных чисел в Идрисе для целей обучения. В моем решении я стремлюсь к полноте для всех функций, и поэтому я использую числа типа Nat
и встроенную функцию modNatNZ
, которая требует доказательства того, что второй аргумент не равен нулю.
При создании программы для проверки моей функции на некоторых больших натуральных числах в качестве входных данных я столкнулся с проблемами, связанными как с проверкой типов, так и с выполнением программы, невероятно медленной.
module Main
%default total
getUnixEpoch : IO Int
getUnixEpoch = foreign FFI_C "#(unsigned long)time(NULL)" (IO Int)
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 (safeMod_m (a * seed + b)) a b m
where
safeMod_m : Nat -> Nat
safeMod_m x = modNatNZ x m (isSuccNotZero prf)
randomNumberGenerator : (seed : Nat) -> Stream Double
randomNumberGenerator seed =
let a : Nat = 16807
b : Nat = 0
m : Nat = 2147483647
in
case m of
Z => ?this_will_never_happen_but_it_makes_type_checking_faster
(S m') => congruentialMethod seed a b (S m')
main : IO ()
main = do seed <- getUnixEpoch
putStrLn $ show $ take 5 $ randomNumberGenerator (cast seed)
1. Проверка типа с большими натуральными числами занимает целую вечность.
Проверка типа, кажется, занимает вечность, чтобы убедиться, что жестко закодированное значение 2147483647 действительно больше нуля. Мое плохое решение - убедить Идриса с помощью выражения-случая.
...
m = 2147483647
in
case m of
Z => ?this_will_never_happen_but_it_makes_type_checking_faster
(S m') => congruentialMethod seed a b (S m')
Очевидно, что мой обходной путь с выражением падежа не очень удовлетворяет. Так есть ли лучший способ убедить средство проверки типов в том, что m больше нуля, чтобы ускорить проверку типов?
Если это что-то, требующее обходного пути, то мне интересно, сможет ли это будущая реализация средства проверки типов в теории справиться за разумное время без обходных путей, или, если это то, что я всегда нужно ожидать, чтобы быстро проверить тип?
2. Выполнение программы с большими натуральными числами занимает вечность.
Я пытался как запустить программу в repl, так и выполнить скомпилированную версию программы, но мне пришлось прервать обе операции вручную, потому что кажется, что для их запуска требуется вечность.
Я немного поэкспериментировал с созданием программы, использующей целые числа (тип Int
), в которой мне удалось добиться высокой производительности во время выполнения, но я не вижу способа сделать все функции total
при создании одной и той же программы с целыми числами.
Есть ли способ определить мою программу со всеми функциями, равными total
, и при этом получить быструю производительность?
Опять же, если в настоящее время не существует хорошего способа получить более высокую производительность во время выполнения для такого рода программ, то мне интересно, можно ли это в конечном итоге / теоретически улучшить в будущих версиях Idris? , или, если это что-то, мне всегда придется обходиться или прибегать к частичным функциям, чтобы получить быструю производительность во время выполнения?
Я использую Idris версии 1.2.0