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编译时遇到这个错误,我坚持在那里你可以帮我理解什么是错的,提前谢谢你
您提供的代码会出现此错误:
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)
所有这些意味着表达式("推断")产生的类型与类型签名("预期")不一致.在这种情况下,getAverage在Statemonad中操作,因此它的类型签名是不正确的,因为它无法评估为非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荷兰国际集团fst在get更简单.所以现在我们有这样的事情:
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)
编辑:既然我忘了的实际得到的结果反馈出来的单子,取代了小细节updateAverage与getAverage特拉维斯布朗的getAverages功能让它在我的代码工作上面.