I thought I was beginning to understand IO in Haskell until I ran into the following problem.
I have the following function, which returns type IO Float:
getFundPrice :: Int -> Int -> IO Float
getFundPrice fund date = do
priceList <- getFundPrice' fund date
let h = head priceList
return h
The function getFundPrice' uses the takusen database library and returns a list of type IO [Float].
I'm able to successfully test the getFundPrice function with Hunit using the following:
p <- getFundPrice 120 20100303
assertEqual
"get fund price"
10.286
(p)
The problem that is stumping me is the following function definition:
lastPos :: Int -> (Shares,Float) -> Period -> Fund -> (Shares,Float)
lastPos endDate begPos [] fund = (fst begPos, trnPrice)
where trnPrice = do
price <- getFundPrice fund endDate
return price
The error I'm getting when attempting to compile is " Couldn't match expected type Float' against inferred type
IO Float'"
I thought the *price <- getFundPrice * action would retrieve the price for me as it does with my HUnit code.
What's different about using this in the where clause?
If you remove the explicit type signature you will see the correct type of:
lastPos :: Int -> (Shares,Float) -> Period -> Fund -> (Shares,IO Float)
Notice the IO Float
at the end. You have defined trnPrice
to be an IO action that retrieves a floating point value. You have not executed that action to retrieve the value! You can not execute that action from anywhere except for the IO monad, which lastPos
is not in. What you can do is:
lastPos :: Int -> (Shares,Float) -> Period -> Fund -> IO (Shares, Float)
lastPos endDate begPos [] fund = do
price <- getFundPrice fund endDate
return (fst begPos, price)
Which lifts all of lastPos
into IO.
The thing about the IO
monad is that you can never get rid of the impure taint. Because your getFundPrice function is not pure, nothing calling it can be pure either.
Your function will have to have the type
lastPos :: Int -> (Shares,Float) -> Period -> Fund -> IO (Shares,Float)
If it helps clarify matters, in your where clause the return
statement wraps the pure price value back up in IO
. There's no way1 to avoid doing this - the IO
monad is designed not to allow it.
In fact it's exactly the same as where trnPrice = getFundPrice fund endDate
1 actually there is a backdoor, but it's not a good idea to use it
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With