从非单子函数中获取随机数
Getting random numbers from non-monadic functions
所以我的目标是能够调用一个非 monadic 函数并让它 return 一个随机值。
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
如果我调用getListFromIO
,一切正常;我得到了我珍贵的随机整数列表,每次都不一样。但是每个调用它的函数都必须使用 IO [Int]
它的类型签名。我不要那个。
我如何构造它以便我能够获得类型为 [Int]
的随机数列表?
IO的目的就是不允许在纯代码中产生副作用。 IO monad 中的所有非纯代码都必须 运行。随机性也基于状态,或从外部资源(全局状态)读取。因此,如果没有黑客攻击,您的尝试是不可能的。我强烈建议您不要使用任何技巧。这种黑客攻击完全绕过了类型系统提供的安全性;它们应该仅限于本地化的安全黑客,主要是当类型系统不够智能并且需要一些说服力时。但这里的情况并非如此——让一个纯函数故意表现得像一个 non-pure 函数在很大程度上不是本地化的 hack,因为任何调用它的代码都会继承破碎的语义,无法跟踪纯度结束的位置和non-purity 开始。
最好重新设计代码,不需要在纯代码中生成随机数。只需从位于 IO 中的代码层次结构中的高层点传递随机性。
你不能,不应该,也不需要这样做。
您声称所有使用 getNums :: IO [Int]
的函数都必须在其类型中包含 IO
。这是不正确的。您可以使用 IO [Int]
操作以多种方式计算的 [Int]
值,例如:
main = do
ints <- getNums -- ints is now of type [Int]
return (map (+1) ints) -- map (+1) does not have IO in its type.
这是引入 Functor
、Applicative
和 Monad
类型类的原因之一:提供一致的方式来处理诸如 IO [Int]
之类的事情当您想避免在任何地方处理 IO
时。
所以我的目标是能够调用一个非 monadic 函数并让它 return 一个随机值。
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
如果我调用getListFromIO
,一切正常;我得到了我珍贵的随机整数列表,每次都不一样。但是每个调用它的函数都必须使用 IO [Int]
它的类型签名。我不要那个。
我如何构造它以便我能够获得类型为 [Int]
的随机数列表?
IO的目的就是不允许在纯代码中产生副作用。 IO monad 中的所有非纯代码都必须 运行。随机性也基于状态,或从外部资源(全局状态)读取。因此,如果没有黑客攻击,您的尝试是不可能的。我强烈建议您不要使用任何技巧。这种黑客攻击完全绕过了类型系统提供的安全性;它们应该仅限于本地化的安全黑客,主要是当类型系统不够智能并且需要一些说服力时。但这里的情况并非如此——让一个纯函数故意表现得像一个 non-pure 函数在很大程度上不是本地化的 hack,因为任何调用它的代码都会继承破碎的语义,无法跟踪纯度结束的位置和non-purity 开始。
最好重新设计代码,不需要在纯代码中生成随机数。只需从位于 IO 中的代码层次结构中的高层点传递随机性。
你不能,不应该,也不需要这样做。
您声称所有使用 getNums :: IO [Int]
的函数都必须在其类型中包含 IO
。这是不正确的。您可以使用 IO [Int]
操作以多种方式计算的 [Int]
值,例如:
main = do
ints <- getNums -- ints is now of type [Int]
return (map (+1) ints) -- map (+1) does not have IO in its type.
这是引入 Functor
、Applicative
和 Monad
类型类的原因之一:提供一致的方式来处理诸如 IO [Int]
之类的事情当您想避免在任何地方处理 IO
时。