首页 > 解决方案 > 在 Haskell 中将 IO [Float] 转换为 [Float]

问题描述

我需要将列表转换IO [Float][Float]. 我IO [Float]从以下函数中得到一个对象:

probs :: Int -> IO [Float]
probs 0 = return []
probs n = do
             p <- getStdRandom random
             ps <- probs (n-1) 
             return (p:ps)

我知道这个函数的结果是一个 [IO Float] 类型的列表,而不是一个数字列表。它是生成数字的 I/O 操作列表。I/O 还没有执行,所以在我的例子中,随机数生成器实际上并没有生成数字。我要做的是生成这个列表内容的每个随机数,这样我就可以得到一个[Float]列表。

我需要这个来计算结果的每个四分位数中的数字数量(检查随机数之间的分布):

calcQuartile :: [Float] -> [Float] -> [Int]
calcQuartile randomList (x1:x2:rest) = length(filter (\x -> x>=x1 && x<x2) randomList):calcQuartile randomList (x2:rest)
calcQuartile x y = []

我使用以下代码运行此功能,但它不起作用:

calcQuartile (probs x) [0,0.25..1]

我得到的错误是:

 • Couldn't match expected type ‘[Float]’
               with actual type ‘IO [Float]’
 • In the first argument of ‘calcQuartile’, namely ‘(probs x)’
   In the expression: calcQuartile (probs x) [0, 0.25 .. 1]
   In an equation for ‘getAmountInQuartile’:
       getAmountInQuartile x = calcQuartile (probs x) [0, 0.25 .. 1]

标签: haskellcastingio

解决方案


编辑:正如@freestyle 风格所指出的,此解决方案有效,但可能导致不可预测的结果:

我导入了模块System.IO.Unsafe

import System.IO.Unsafe

接下来,我可以用以下代码替换我的代码:

calcQuartile (unsafePerformIO(probs x)) [0,0.25..1]

正如@Willem Van Onsem 所指出的,更好的解决方案如下:

probs x >>= \y -> return (calcQuartile y [0, 0.25..1])

值得注意的是,这将返回 aIO [Int]而不是 a [Int]。monadic绑定 >>=将两个不纯的动作链接在一起(即在本例中为 IO 动作)并从它们中生成单个IO动作。同样的事情也可以用do符号来写:

do
  y <- probs x
  return $ calcQuartile y [0, 0.25 .. 1]

在这种特殊情况下,第二个动作( the calcQuartile)实际上是的(因此 the return,它将纯值包装为无副作用的 IO 动作),因此您根本不需要 monad 实例,而只需用作IO函子:

fmap (\y -> calcQuartile y [0, 0.25..1]) $ probs x

或者

(`calcQuartile`[0, 0.25..1]) <$> probs x

推荐阅读