蒙纳德·哈斯克尔州 [英] state monad haskell

查看:131
本文介绍了蒙纳德·哈斯克尔州的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想编写一个用于使用Haskell中的State Monad计算平均值的函数 这是我到目前为止编写的代码

I want to write a function for calculating the average using the State Monad in haskell this is the code I wrote as far

import Control.Monad.State
type MyState = (Double,Double)
media s (a,n)= ((a*n+s)/(n+1),n+1)

getAverage:: Double ->State MyState  s1-> Double
getAverage s c=get >>= \s0 -> let (x,s1) =media s s0
            in put s1 >> return x

在GHCI中编译时出现此错误,并且卡在了那里 您能帮助我了解问题出在哪吗?

I got this error when compile in GHCI, and I stuck there can you help me to understand what is wrong, thank you in advance

推荐答案

您提供的代码会出现此错误:

The code you provided gives this error:

Couldn't match expected type `Double'
       against inferred type `m Double'
In the expression:
      get >>= \ s0 -> let (x, s1) = ... in put s1 >> return x
In the definition of `getAverage':
    getAverage s c = get >>= \ s0 -> let ... in put s1 >> return x

这意味着从表达式(推断")得到的类型与类型签名(期望")不同.在这种情况下,getAverageState monad中运行,因此类型签名是错误的,因为它不能求值为非monadic类型.

All this means is that the type resulting from the expression ("inferred") disagrees with the type signature ("expected"). In this case, getAverage operates in the State monad, so it's the type signature that's incorrect, as it can't evaluate to a non-monadic type.

但是,您的代码除此之外还有其他问题,即使解决了特定问题也不会编译.首先是一些使其更具可读性的样式问题:

Your code has other problems besides that, however, and won't compile even after fixing that particular issue. First a few stylistic issues to make it more readable:

  • getAverage具有未使用的参数,该参数应该是State monad中的一个值,无论如何实际上没有任何意义.
  • 使用do表示符号通常比使用(>>=)和lambda更清晰,尤其是对于State之类的东西.
  • 第二行的缩进令人困惑,因为in与位于 lambda内的let匹配.
  • getAverage has an unused parameter, which is supposedly a value in the State monad, which doesn't really make sense anyway.
  • Using the do notation is usually clearer than using (>>=) and lambdas, especially for something like State.
  • The indentation of the second line is confusing, since the in goes with the let that's inside the lambda.

进行这些更改后,我们会得到:

Making those changes we have this:

getAverage s = do
    s0 <- get
    let (x, s1) = media s s0
    put s1 
    return x

...这使得更容易发现下一个错误:media的第二个参数是2元组,而s1只是一个数字,但是您试图将两个都用于状态价值.可能您想要将状态设置为(x, s1),但仅返回x.

...which makes it easier to spot the next error: The second argument of media is a 2-tuple, and s1 is just a single number, but you're trying to use both for the state value. Probably what you wanted was to set the state to (x, s1), but return only x.

getAverage s = do
    s0 <- get
    let (x,s1) = media s s0
    put (x,s1)
    return x

这可以很好地编译,但是仍然需要一些整理:

This compiles just fine, but still needs some tidying:

  • media需要更新整个状态值,因此,只需使用modify函数,而不是get ting和put ting.
  • 返回值是状态值的第一部分,因此只需fmapfst替换为get更为简单.
  • media needs to update the entire state value, so rather than getting and putting, just use the modify function.
  • The return value is the first part of the state value, so just fmaping fst over get is more straightforward.

所以现在我们有了这样的东西:

So now we have something like this:

media :: Double -> MyState -> MyState
media s (a, n) = ((a * n + s) / (n + 1), n + 1)

getAverage:: Double -> State MyState Double
getAverage s = do
    modify (media s)
    fmap fst get

我们还可以注意到getAverage可以做两种不同的事情,并将其拆分为单独的功能:

We can also note that getAverage is kind of doing two different things, and split it into separate functions:

updateAverage:: Double -> State MyState ()
updateAverage s = modify (media s)

currentAverage :: State MyState Double
currentAverage = fmap fst get

getAverage:: Double -> State MyState Double
getAverage s = updateAverage s >> currentAverage

编辑:由于我忘记了将结果实际从单子中取出的小细节,因此在Travis Brown的getAverages函数中将updateAverage替换为getAverage可以使它正常工作在上面的代码中.

Edit: And since I forgot about the minor detail of actually getting the results back out of the monad, replacing updateAverage with getAverage in Travis Brown's getAverages function will let it work on my code above.

这篇关于蒙纳德·哈斯克尔州的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆