where 子句中的 IO

发布于 2024-10-27 17:13:22 字数 1177 浏览 3 评论 0原文

我以为我开始理解 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” '针对推断类型IO Float'”

我认为 *price <- getFundPrice * 操作将为我检索价格,就像使用我的 HUnit 代码一样。

在 where 子句中使用 this 有什么不同?

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 typeIO 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

晚雾 2024-11-03 17:13:22

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

lastPos :: Int -> (Shares,Float) -> Period -> Fund -> (Shares,IO Float)

注意末尾的 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)

将所有 lastPos 提升到 IO 中。

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.

清秋悲枫 2024-11-03 17:13:22

IO monad 的问题是你永远无法摆脱不纯的污点。因为您的 getFundPrice 函数不是纯粹的,所以调用它的函数也不是纯粹的。

您的函数必须具有以下类型:

lastPos :: Int -> (Shares,Float) -> Period -> Fund -> IO (Shares,Float)

如果有助于澄清问题,请在您的 where 子句中的 return 语句中将纯价格值包装回 IO 中。没有办法1避免这样做 - IO monad 被设计为不允许这样做。

事实上,它与 where trnPrice = getFundPrice Fund endDate 1 完全相同,

实际上有一个 后门,但使用它不是一个好主意

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文