简体   繁体   中英

Getting random numbers from non-monadic functions

So my goal is to be able to call a non-monadic function and have it return a random value.

getNums :: [Int] -- this only works when the type signature is "IO [Int]"
getNums = getListFromIO 10

getListFromIO :: Int -> IO [Int]
getListFromIO n = do
  gen <- newStdGen
  return $ generateList n gen

generateList :: Int -> StdGen -> [Int]
generateList n gen = take n $ randomRs (1,9) $ gen

If I call getListFromIO , all is well; I get my precious random list of integers, and it is different every time. But every function that calls it must use IO [Int] it the type signature. I don't want that.

How can I structure this so that I am able to get a random number list of type [Int] ?

You can't, shouldn't, and don't need to do this.

You claim that all functions which use getNums :: IO [Int] must have IO in their type. This is simply not true. You can work with the [Int] value that the IO [Int] action computes in a number of ways, for example:

main = do
  ints <- getNums -- ints is now of type [Int]
  return (map (+1) ints) -- map (+1) does not have IO in its type.

This is one of the reasons that the Functor , Applicative , and Monad typeclasses were introduced: to provide a consistent way to work with things like IO [Int] when you want to avoid dealing with IO everywhere.

The purpose of IO is exactly to not allow side effects in pure code. All nonpure code must run in the IO monad. Randomness is also based on state, or reading from an external resource (global state). So what you are attempting is impossible without hacks. And I would strongly urge you to not use any hacks. Such hacks completely bypass the safety offered by the type system; they should only be limited to localized, safe hacks, primarily when the type system isn't smart enogh and needs some convincing. But that's not the case here — making a pure function deliberately behave like a non-pure one is very much not a localized hack as any code that calls it will inherit the broken semantics with no way for keeping track of where purity ends and non-purity begins.

It's best if you redesign your code to not need to generate random numbers in pure code. Just pass the randomness in from a high level point in your code hierarchy that lives in IO.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM