2014-02-22 3 views
1

В настоящее время я изучаю Haskell, и у меня есть трудное время, чтобы посмотреть, Каковы общие способы сберечь посредников, приводящих к Haskell.Haskell - сохранить промежуточный результат в памяти

Например, предположим, что у меня есть программа, которая принимает файл, производит некоторые промежуточные результаты, а затем принимает некоторые параметры и использует результат первого шага для создания чего-то другого. Кроме того, предположим, что в конце пользователь может изменить параметры для создания нового вывода, но обработка первого шага не должна быть переделана, чтобы сократить время вычисления.

В принципе, мне просто нужно временно сохранить результат первого шага. Это было бы довольно просто для меня способом OO, но из-за чистоты 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 как способ сигнализации и блокировки разделов кода на основе некоторого общего состояния, но даже это может быть сложно сделать правильно. На самом высоком уровне ST и STM позволяют обрабатывать разделяемое состояние гораздо более сложными способами и легче рассуждать.

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 в данном случае) хранятся для использования других частями программы.

Смежные вопросы