Вопрос

Я хотел бы сгенерировать бесконечный поток чисел с помощью Rand monad из Системный.Случайный.MWC.Монада.Если бы только был экземпляр MonadFix для этой монады, или экземпляр, подобный этому:

instance (PrimMonad m) => MonadFix m where
     ...

тогда можно было бы написать:

runWithSystemRandom (mfix (\ xs -> uniform >>= \x -> return (x:xs)))

Но такового здесь нет.

Я проходил через это Документы MonadFix но я не вижу очевидного способа реализации этого экземпляра.

Это было полезно?

Решение

Вопрос: Как вы хотите создать свое начальное семя?

Проблема в том, что MWS построен на «примитивном» пакете, который абстрагирует только IO и строго (Control.Monad.st.st S). Это также не абстрактно лениво (Control.monad.st.lazy.st S).

Возможно, можно было бы привести к экземплярам «примитива», чтобы покрыть ленивый ST, а затем MWS может быть ленивым.

Обновление: я могу сделать эту работу с помощью control.monad.st.lazy, используя Stricttolazyst:

module Main where

import Control.Monad(replicateM)
import qualified Control.Monad.ST as S
import qualified Control.Monad.ST.Lazy as L
import qualified System.Random.MWC as A

foo :: Int -> L.ST s [Int]
foo i = do rest <- foo $! succ i
           return (i:rest)

splam :: A.Gen s -> S.ST s Int
splam = A.uniformR (0,100)

getS :: Int -> S.ST s [Int]
getS n = do gen <- A.create
            replicateM n (splam gen)

getL :: Int -> L.ST s [Int]
getL n = do gen <- createLazy
            replicateM n (L.strictToLazyST (splam gen))

createLazy :: L.ST s (A.Gen s)
createLazy = L.strictToLazyST A.create

makeLots :: A.Gen s -> L.ST s [Int]
makeLots gen = do x <- L.strictToLazyST (A.uniformR (0,100) gen)
                  rest <- makeLots gen
                  return (x:rest)

main = do
  print (S.runST (getS 8))
  print (L.runST (getL 8))
  let inf = L.runST (foo 0) :: [Int]
  print (take 10 inf)
  let inf3 = L.runST (createLazy >>= makeLots) :: [Int]
  print (take 10 inf3)

Другие советы

Вы можете написать экземпляр MonadFix.Однако код не будет генерировать бесконечный поток различных случайных чисел.Аргумент mfix - это функция, которая вызывает uniform ровно один раз.Когда код будет запущен, он вызовет uniform ровно один раз и создайте бесконечный список, содержащий результат.

Вы можете попробовать эквивалентный код ввода-вывода, чтобы посмотреть, что произойдет:

import System.Random
import Control.Monad.Fix
main = print . take 10 =<< mfix (\xs -> randomIO >>= (\x -> return (x : xs :: [Int])))

Похоже, что вы хотите использовать генератор случайных чисел с сохранением состояния, и вы хотите запустить генератор и лениво собрать его результаты.Это невозможно без тщательного использования unsafePerformIO.Если вам не нужно быстро генерировать много случайных чисел, вы можете использовать чистую функцию RNG, такую как randomRs вместо этого.

(Это было бы лучше подходить как комментарий к ответу на Хипсинк, но это слишком долго.)

MonadFix случаи должны придерживаться Несколько законов. Анкет Один из них является оставляя сжимание/:

mfix (\x -> a >>= \y -> f x y)  =  a >>= \y -> mfix (\x -> f x y)

Этот закон позволяет переписать ваше выражение как

mfix (\xs -> uniform >>= \x -> return (x:xs))
= uniform >>= \x -> mfix (\xs -> return (x:xs))
= uniform >>= \x -> mfix (return . (x :))

Используя другой закон, чистота mfix (return . h) = return (fix h), мы можем дополнительно упростить

= uniform >>= \x -> return (fix (x :))

и использование стандартных законов Монады и переписывания fix (x :) в качестве repeat x

= liftM (\x -> fix (x :)) uniform
= liftM repeat uniform

Следовательно, результатом действительно является один вызов uniform а затем просто повторяя одно значение на неопределенный срок.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top