【问题标题】:Summing up a list of IO Float: [IO Float] in Haskell总结一下 IO Float 列表:[IO Float] in Haskell
【发布时间】:2016-04-09 09:47:56
【问题描述】:

所以我在玩一些 Haskell,试图自己学习它。我正在尝试解决某个问题,我应该创建一个随机数列表,然后将它们总结起来。

我有生成它们的代码 - 使用 getStdRandomrandomR。使用它们都返回IO Float的列表:[IO Float]

现在,当我尝试使用 foldl 或 foldr 对列表求和,甚至尝试简单的递归求和时,我会遇到错误等 - 据我了解,这是因为 IO Float 是一个单子,所以我需要做一些 Haskell 魔法让它工作。

我一直在谷歌搜索,但没有找到有效的方法。

有什么方法可以总结列表吗?甚至将其转换为浮点数列表,以便在代码的其他部分更容易解决?

【问题讨论】:

  • 请添加您拥有的代码 - 解决方案可能像 sum <$> whateverYouHaveNow 一样简单

标签: list haskell functional-programming sum monads


【解决方案1】:

请注意,[IO Float] 类型的列表不是数字列表。它是生成数字的 I/O 操作列表。 I/O 尚未执行,因此在您的情况下,随机数生成器实际上并未生成数字。

您可以使用sequence :: Monad m => [m a] -> m [a] 函数将 IO 操作列表组合成一个提供结果列表的 IO 操作:

do the_numbers <- sequence your_list
   return $ sum the_numbers

或者,您可以使用foldM 函数编写一元折叠:

sumIONumbers :: [IO Float] -> IO Float
sumIONumbers xs = foldM f 0.0 xs
  where
    f acc mVal = do
      val <- mVal  -- extract the Float from the IO
      return $ acc + val

如 cmets 中所述,您还可以利用每个 Monad 也是 Functor 的事实(这在较新的版本中强制执行),因此您可以使用 fmap :: Functor f =&gt; (a -&gt; b) -&gt; f a -&gt; f b 在 IO 中应用函数:

fmap sum (sequence your_list)

或者使用中缀同义词&lt;$&gt;

sum <$> sequence your_list

【讨论】:

  • 第一个do 语句可以简化为fmap sum (sequence yourList)sum &lt;$&gt; sequence yourList。 (其中fmap :: Functor f =&gt; (a -&gt; b) -&gt; f a -&gt; f b(&lt;$&gt;) = fmap
  • 不是数字列表”——完全正确。看到这一点的一个简单方法是多次评估sequence your_list:每次都会得到不同的结果!
【解决方案2】:

使用 liftM 进行如下操作怎么样:

import System.Random
import Control.Monad

rnd :: IO Float
rnd = getStdRandom (randomR (0.0,1.0))

main = do
  let l = map (\_ -> rnd) [1..10]
  n <- foldl (liftM2 (+)) (return (0 :: Float)) l
  print n

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-28
    • 1970-01-01
    • 2015-02-28
    • 2012-07-13
    • 2020-02-03
    • 2012-03-28
    • 1970-01-01
    • 2015-07-17
    相关资源
    最近更新 更多