州monad haskell

arp*_*pho 2 monads haskell state-monad

我想编写一个函数来计算平均值,使用状态Monad in haskell这是我写的代码

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
Run Code Online (Sandbox Code Playgroud)

我在GHCI编译时遇到这个错误,我坚持在那里你可以帮我理解什么是错的,提前谢谢你

C. *_*ann 6

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

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
Run Code Online (Sandbox Code Playgroud)

所有这些意味着表达式("推断")产生的类型与类型签名("预期")不一致.在这种情况下,getAverageStatemonad中操作,因此它的类型签名是不正确的,因为它无法评估为非monadic类型.

但是,除此之外,您的代码还有其他问题,即使在修复该特定问题后也无法编译.首先是一些风格问题,使其更具可读性:

  • getAverage有一个未使用的参数,据说是Statemonad中的一个值,无论如何它都没有意义.
  • 使用do符号通常比使用(>>=)和lambdas 更清晰,特别是对于类似的东西State.
  • 第二行的缩进是混乱的,因为in去与let里面的拉姆达.

做出这些改变我们有这个:

getAverage s = do
    s0 <- get
    let (x, s1) = media s s0
    put s1 
    return x
Run Code Online (Sandbox Code Playgroud)

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

getAverage s = do
    s0 <- get
    let (x,s1) = media s s0
    put (x,s1)
    return x
Run Code Online (Sandbox Code Playgroud)

编译得很好,但仍需要一些整理:

  • media需要更新整个状态值,而不是getting和putting,只需使用该modify函数.
  • 返回值是状态值的第一部分,所以只是fmap荷兰国际集团fstget更简单.

所以现在我们有这样的事情:

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
Run Code Online (Sandbox Code Playgroud)

我们还可以注意到,getAverage它有两种不同的东西,并将其拆分为单独的函数:

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
Run Code Online (Sandbox Code Playgroud)

编辑:既然我忘了的实际得到的结果反馈出来的单子,取代了小细节updateAveragegetAverage特拉维斯布朗的getAverages功能让它在我的代码工作上面.