所以我的目标是能够调用非monadic函数并让它返回一个随机值。
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]
类型的随机数列表?
答案 0 :(得分:4)
你不能,不应该,也不需要这样做。
您声称使用getNums :: IO [Int]
的所有功能必须在其类型中包含IO
。这是不正确的。您可以使用[Int]
操作计算的IO [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
。
答案 1 :(得分:2)
IO的目的正是在纯代码中不允许副作用。所有非纯代码必须在IO monad中运行。随机性也基于状态,或从外部资源(全局状态)读取。所以如果没有黑客,你所尝试的是不可能的。我强烈建议你不要使用任何黑客。这种黑客完全绕过了类型系统提供的安全性;它们应该仅限于本地化,安全的黑客攻击,主要是当类型系统不具备智能并且需要一些令人信服的时候。但这不是这里的情况 - 使一个纯粹的函数故意表现得像一个非纯函数非常不是本地化的黑客,因为任何调用它的代码都会继承破坏的语义而无法跟踪纯度的位置结束和非纯度开始。
如果您重新设计代码以便不需要在纯代码中生成随机数,那么这是最好的。只需从位于IO中的代码层次结构中的高级别点传递随机性。