Haskell - 将中间结果保存在内存中

时间:2014-02-22 19:58:52

标签: haskell memory

我目前正在学习Haskell,我很难看到保存中介的常用方法是什么导致Haskell。

例如,假设我有一个程序来获取文件,生成一些中间结果然后获取一些参数并使用第一步的结果来生成其他内容。另外,让我们说最后用户可以更改参数以产生新输出,但不应重做第一步的处理以减少计算时间。

基本上,我只需要暂时保存第一步的结果。对于我来说,这对OO来说相当简单,但由于Haskell的纯度,我没有看到解决这个问题的便捷方法。

2 个答案:

答案 0 :(得分:3)

在Haskell中有很多方法可以处理中间结果。听起来我希望你的main函数看起来像这样。我假设您有一些产生中间结果的函数(runFirstStep),一个提示设置的函数(promptForSettings),以及一个使用中间结果和设置产生最终值的函数(runSecondStep

main :: IO ()
main = do
  -- setup, compute shared value
  intermediate <- runFirstStep
  -- processing
  -- prompt for settings here
  settings <- promptForSettings
  final <- runSecondStep intermediate settings
  -- and done
  print final

如果你想要一个更复杂的控制流,你可以定义一个单独的函数,如下所示:

main :: IO ()
main = do
  -- setup, compute shared value
  intermediate <- runFirstStep
  -- run the second step computation
  processLoop intermediate
  print final

processLoop :: intermediate -> IO final
processLoop intermediate = do
  settings <- promptForSettings
  final <- runSecondStep intermediate settings
  -- check if user wants to run with different settings
  rerun <- do
    putStrLn "Run again? [Y/n]"
    result <- getStrLn
    return (result != "n")
  if rerun
  then process
  else return final

如果您对更复杂的控制流感兴趣,有许多方法可以使用各种技术在存储器中存储中间计算。最低级别和最难做的是使用IORef。在此之上,您可以使用MVar作为基于某些共享状态的信令和锁定代码段的方式,但即使这样做也可能很难。在最高级别,STSTM可让您以更复杂的方式处理共享状态,并且更容易推理。

答案 1 :(得分:2)

一个例子:你想要阅读一堆数字,然后计算这些数字的不同权力和(平方和,立方总和等)。

第一步是“忽略IO” - 暂时忘记如何获得数字和功率参数 - 并专注于完成工作的功能 - 计算第n个的总和数字列表的权力。

powersum :: [Double] -> Int -> Double
powersum xs n = sum $ map (^n) xs

我们想要计算各种指数的功率和。再说一遍,我会忘记你以后要用它们做什么,无论是打印它们,排序它们等等,并编写一个执行计算的函数:

powersums :: [Double] -> [Int] -> [Double]
powersums xs ns = map (powersum xs) ns

现在让我们把它连接到现实世界。让我们首先考虑事先知道指数的情况,但是从标准输入中读取数字(全部在一行上)。

main = do line <- getLine                         -- IO
          let nums = map read (words line)        \
          let exponents = [1..10]                  | - pure code
          let sums = powersums nums exponents     /
          print sums                              -- IO

请注意我们的IO如何将我们的纯代码三明治 - 这是功能程序的典型特征。

现在假设您还想从stdin中读取指数,并打印出每个读指数的幂和。你可以写一个像这样的命令式程序:

main = do line <- getLine
          let nums = map read (words line)
          forever $ do exp <- read `fmap` getLine
                       putStrLn $ show $ powersum nums exp

这说明了如何存储数据(在这种情况下为nums)以供程序的其他部分使用。