2014-02-22 51 views
1

我當前正在學習Haskell,而且我很難看到在Haskell中保存中間結果的常用方法是什麼。Haskell - 將中間結果保存在內存中

例如,假設我有一個程序需要一個文件,產生一些中間結果,然後獲取一些參數並使用第一步的結果產生其他內容。另外,假設最終用戶可以改變參數以產生新的輸出,但是爲了減少計算時間,不應該重做第一步的處理。

基本上,我只需要暫時保存第一步的結果。對於我來說,這對於我來說相當簡單,但由於Haskell的純度,我沒有看到解決這個問題的方便方法。

回答

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可讓您以更復雜的方式處理共享狀態,並且更容易推理。

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在這種情況下)被儲存供程序的其他部分。