IO in where子句

Nei*_*eil 5 io monads haskell

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

Tho*_*son 8

如果删除显式类型签名,您将看到正确的类型:

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.

  • @Neil,这是一个常见的误解,如果你的程序执行了很多IO,那么你的程序必须在任何地方都有IO.它只是意味着你必须设计IO在外面.这通常很容易 - 它会使您以数学方式而不是操作方式对对象进行建模.在您的示例中,只需让您的业务逻辑函数将核心数据作为参数(它们依赖于*核心数据,对吗? - 这使它们成为函数). (6认同)

Rob*_*gar 5

关于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实际上有一个后门,但使用它并不是一个好主意