我认为我开始理解Haskell中的IO,直到遇到以下问题。
我有以下函数,它返回IO Float类型:
getFundPrice :: Int -> Int -> IO Float
getFundPrice fund date = do
priceList <- getFundPrice' fund date
let h = head priceList
return h
函数getFundPrice'使用takusen数据库库并返回类型为IO [Float]的列表。
我可以使用以下方法使用Hunit成功测试getFundPrice函数:
p <- getFundPrice 120 20100303
assertEqual
"get fund price"
10.286
(p)
困扰我的问题是以下函数定义:
lastPos :: Int -> (Shares,Float) -> Period -> Fund -> (Shares,Float)
lastPos endDate begPos [] fund = (fst begPos, trnPrice)
where trnPrice = do
price <- getFundPrice fund endDate
return price
我在尝试编译时遇到的错误是“无法匹配预期类型Float' against inferred type
IO Float”“
我认为* price&lt; - getFundPrice * 操作会检索我的价格,就像我的HUnit代码一样。
在where子句中使用它有什么不同?
答案 0 :(得分:8)
如果删除显式类型签名,您将看到正确的类型:
lastPos :: Int -> (Shares,Float) -> Period -> Fund -> (Shares,IO Float)
注意最后的IO Float
。您已将trnPrice
定义为检索浮点值的IO操作。你有不执行该操作来检索值!除了lastPos
不在的IO monad之外,您无法从任何地方执行该操作。您可以做的是:
lastPos :: Int -> (Shares,Float) -> Period -> Fund -> IO (Shares, Float)
lastPos endDate begPos [] fund = do
price <- getFundPrice fund endDate
return (fst begPos, price)
将所有lastPos
提升为IO。
答案 1 :(得分:5)
关于IO
monad的事情是,你永远无法摆脱不纯的污点。因为你的getFundPrice函数不是纯粹的,所以调用它的任何东西都不是纯粹的。
您的功能必须具有
类型lastPos :: Int -> (Shares,Float) -> Period -> Fund -> IO (Shares,Float)
如果它有助于澄清问题,那么在{where}条款中,return
语句将纯价格值包含在IO
中。 1 没有办法避免这样做 - IO
monad被设计为不允许它。
实际上它与where trnPrice = getFundPrice fund endDate
1 实际上有一个backdoor,但使用它不是一个好主意