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