我正在尝试编写一个函数,StateT只是为了更多地了解它.
在f,我想访问Int最后一个类型的参数StateT [Int] IO Int:
f :: StateT [Int] IO Int
f = state $ \xs -> update (error "I want a") xs
update :: Int -> [Int] -> (Int, [Int])
update x [] = (x, [])
update x (y:ys) = (x+y, ys)
Run Code Online (Sandbox Code Playgroud)
以下是我想称之为:
let x = return 55 :: StateT [Int] IO Int
参考runStateT:
*Main> :t runStateT
runStateT :: StateT s m a -> s -> m (a, s)
Run Code Online (Sandbox Code Playgroud)
我希望能运行它:
runStateT (f x) [1,2,3]
从GHCI获得以下内容,即IO (Int, [Int])获得打印:
(56, [2,3])
Run Code Online (Sandbox Code Playgroud)
由于内a,即55,+ 1即从[1,2,3],退货(56, [2,3]).
如何编写上述函数,获取访问权限a?
好的,这就是你想要的:
>>> let x = return 55 :: StateT [Int] IO Int
>>> runStateT (f x) [1,2,3]
(56, [2,3])
Run Code Online (Sandbox Code Playgroud)
所以让我们从那里开始倒退.
从使用上f,我们可以推断出它的类型 -
f :: StateT [Int] IO Int -> StateT [Int] IO Int
Run Code Online (Sandbox Code Playgroud)
请注意f问题中给定类型的差异- 即f类型值之间的函数StateT [Int] IO Int,而不是该类型的值.
要定义f,我们需要(>>=) :: Monad m => m a -> (a -> m b) -> m b.这将允许我们获取类型的输入StateT [Int] IO Int并Int在输入计算上运行一些计算.
f x = x >>= \i -> state (splitAt 1) >>= \[j] -> return (i + j)
Run Code Online (Sandbox Code Playgroud)
或者,使用do-notation:
f x = do
i <- x
[j] <- state (splitAt 1)
return (i + j)
Run Code Online (Sandbox Code Playgroud)
这给了我们我们想要的结果.
虽然这有效,但它非常非惯用.不是将monadic值作为输入传递给函数并将它们绑定到函数内部,而是使用外部的bind运算符(>>=)来定义采用常规值并返回monadic值的函数.
所以定义更为正常
shiftAdd :: Int -> StateT [Int] IO Int
shiftAdd i = do
[j] <- state (splitAt 1)
return (i + j)
Run Code Online (Sandbox Code Playgroud)
所以现在我们不仅可以运行
>>> runStateT (shiftAdd 55) [1,2,3]
(56,[2,3])
Run Code Online (Sandbox Code Playgroud)
但是也
>>> runStateT (shiftAdd 55 >>= shiftAdd >>= shiftAdd)
(61,[])
Run Code Online (Sandbox Code Playgroud)
它仍然不像以下那样惯用:
splitAt(如果状态列表为空,它将抛出异常)解决这个问题给了我们:
shiftAdd' :: (Monad m, Num a) => a -> StateT [a] m a
shiftAdd' i = state $ \js -> case js of
[] -> (i, [])
j : js -> (i + j, js)
Run Code Online (Sandbox Code Playgroud)
哪个工作得很好:
>>> runStateT (return 55 >>= shiftAdd') [1,2,3]
(56,[2,3])
>>> runStateT (return 55 >>= shiftAdd' >>= shiftAdd' >>= shiftAdd') [1,2,3]
(61,[])
>>> runStateT (return 55 >>= shiftAdd' >>= shiftAdd' >>= shiftAdd') []
(55,[])
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
97 次 |
| 最近记录: |