【问题标题】:Haskell - save intermediary result in memoryHaskell - 将中间结果保存在内存中
【发布时间】:2014-02-22 19:58:52
【问题描述】:

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

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

基本上,我只需要暂时保存第一步的结果。以面向对象的方式,这对我来说相当简单,但由于 Haskell 的纯度,我看不到解决此问题的便捷方法。

【问题讨论】:

    标签: haskell memory


    【解决方案1】:

    在 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 可以让您以更复杂的方式处理共享状态,并且更容易推理。

    【讨论】:

      【解决方案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 是如何将我们的纯代码夹在中间的——这是非常典型的函数式程序。

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

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

      这说明了如何存储数据(在本例中为nums)以供程序的其他部分使用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-07-24
        • 2016-02-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多