Базовая функция генератора псевдослучайных чисел в Haskell - PullRequest
0 голосов
/ 09 октября 2019

Я пытаюсь написать простой генератор псевдослучайных чисел с использованием алгоритма Лемера, чтобы лучше понять, как обрабатывать значения ввода-вывода в Haskell, и я продолжаю получать несоответствия типов.

Мой код выглядит следующим образом:

import Data.Time.Clock.POSIX

generator :: Int -> Int -> Int -> Int
generator x i m
  | i <= 0 = error "Index out of bounds"
  | i == 1 = x * ( x `mod` m )
  | otherwise = generator (generator x (i - 1) m) 1 m

pseudorand :: Int -> Int -> IO Int
pseudorand i m = do t <- round `fmap` getPOSIXTime
                    return ( \ i m -> generator t i m )

Функция генератора получает начальное число, число итераций и параметр по модулю и выполняет рекурсивное вычисление по модулю, где x_(i+1) = x_0 * x_i mod m, достаточно просто. Получение миллисекундного времени как IO Int также выполнимо. Проблема, с которой я сталкиваюсь, заключается в том, чтобы потом передать IO Int на функцию генератора.

Приведенный выше код ожидает IO Int, но получает IO (Int -> Int -> Int). Это, очевидно, тип моей функции генератора, поэтому я попытался

pseudorand :: Int -> Int -> IO Int
pseudorand i m = do t <- round `fmap` getPOSIXTime
                    return ( fmap generator t i m )

, который ожидает Int, но получает Int -> Int.

Почему он не ожидает ввода? Почему он не видит i и m?

Также был бы признателен за ваш вклад в то, как вы написали бы код для этого

1 Ответ

2 голосов
/ 09 октября 2019

Это просто

pseudorand :: Int -> Int -> IO Int
pseudorand i m = do
  t <- round <$> getPOSIXTime -- infix fmap is (<$>), evoking "fancy function application"
  -- here, t :: Int, i :: Int, m :: Int, so generator t i m :: Int
  -- t IS NOT an IO Int: the whole point of do-notation is "unwrapping" (<-)
  -- monadic values and using them like normal ones
  -- return (generator t i m) :: IO Int; we're done
  return $ generator t i m

Вы также можете написать это в аппликативном стиле:

pseudorand i m = generator <$> (round <$> getPOSIXTime) <*> pure i <*> pure m
-- read this as: generator(round(getPOSIXTIME()), i, m)
-- as you would write in an imperative language

Или только с одним инфиксным fmap:

pseudorand i m = (\t -> generator (round t) i m) <$> getPOSIXTime
...