Reputation: 75
I am currently learning Haskell and I have a hard time to see What are the common ways to save intermediaries result in Haskell.
For example, let's say that I have a program that take a file, produce some intermediary results and then take some parameters and use the result of the first step to produce something else. Plus, let's say that at the end the user could change the parameters to produce new output but the processing of the first step should not be redone in order to reduce the computation time.
Basically, I just need to temporally save the result of the first step. This would be fairly simple for me in a OO way but because of Haskell purity I don't see a convenient way to solve this.
Upvotes: 1
Views: 962
Reputation: 52029
An example: You want to read in a bunch of numbers and then compute different sums of powers of those numbers (sums of squares, sums of cubes, etc.)
The first step is to "ignore the IO" - forget for the moment how you are going to get the numbers and the power parameter - and concentrate on the function that does meat of the work - computes the sums of n-th powers of a list of numbers.
powersum :: [Double] -> Int -> Double
powersum xs n = sum $ map (^n) xs
We'll want to compute power sums for various exponents. Again, I would forget about what you are going to do with them later, whether it be print them out, sort them, etc. and write a function which does the computation:
powersums :: [Double] -> [Int] -> [Double]
powersums xs ns = map (powersum xs) ns
Now let's hook it up to the real world. Let's first consider the case when we know the exponents in advance but read the numbers from standard input (all on a single line.)
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
Note how our IO sandwiches our pure code - this is very typical of functional programs.
Now suppose you want to also read in the exponents from stdin, and print out the power sums of each read exponent. You could write an imperative-style program like this:
main = do line <- getLine
let nums = map read (words line)
forever $ do exp <- read `fmap` getLine
putStrLn $ show $ powersum nums exp
This illustrates how data (nums
in this case) is being stored for use by other parts of the program.
Upvotes: 2
Reputation: 1095
There are many ways to deal with intermediate results in Haskell. It sounds to me like you would like your main
function to look something like this. I will assume you have some function that produces an intermediate result (runFirstStep
), a function that prompts for settings (promptForSettings
), and a function that uses the intermediate result and the settings to produce a final value (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
If you want a more complex control-flow, you could define a separate function, like so:
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
If you are interested in more complex control flows that are impure, there are many ways to store intermediate computations in memory using a variety of techniques. The lowest level and most difficult to get right is to use IORef
. Above that, you can use MVar
as a way of signalling and locking sections of code based on some shared state, but even that can be tricky to get right. At the highest level, ST
and STM
let you handle shared state in much more complex ways and are easier to reason about.
Upvotes: 3