IO in where子句

时间:2011-03-29 04:28:05

标签: haskell io monads

我认为我开始理解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子句中使用它有什么不同?

2 个答案:

答案 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,但使用它不是一个好主意