首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >访问StateT中的“a”

访问StateT中的“a”
EN

Stack Overflow用户
提问于 2017-05-17 12:43:31
回答 1查看 115关注 0票数 0

我试图用StateT编写一个函数,只是为了了解更多有关它的信息。

f中,我想访问上一种类型的StateT [Int] IO Int参数中的Int

代码语言:javascript
复制
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) 

我想这样称呼它:

let x = return 55 :: StateT [Int] IO Int

参考runStateT

代码语言:javascript
复制
*Main> :t runStateT
runStateT :: StateT s m a -> s -> m (a, s)

我想要运行它:

runStateT (f x) [1,2,3]

要从GHCI获取以下内容,即打印IO (Int, [Int])

代码语言:javascript
复制
(56, [2,3])

因为内部a,即55+ 1,即从[1,2,3]返回(56, [2,3])

如何编写上面的函数,访问a

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-05-17 15:38:50

好吧,下面是你想要的:

代码语言:javascript
复制
>>> let x = return 55 ::  StateT [Int] IO Int
>>> runStateT (f x) [1,2,3]
(56, [2,3])

因此,让我们从这倒向后看。

f的使用,我们可以推断出它的类型-

代码语言:javascript
复制
f :: StateT [Int] IO Int -> StateT [Int] IO Int

注意问题中给定的f类型的不同--即fStateT [Int] IO Int类型的值之间的函数,而不是该类型的值。

要定义f,我们需要(>>=) :: Monad m => m a -> (a -> m b) -> m b。这将允许我们接受StateT [Int] IO Int类型的输入,并在输入计算的Int上运行一些计算。

代码语言:javascript
复制
f x = x >>= \i -> state (splitAt 1) >>= \[j] -> return (i + j)

或者使用do-表示法:

代码语言:javascript
复制
f x = do
  i <- x
  [j] <- state (splitAt 1)
  return (i + j)

这正好给了我们想要的结果。

虽然这是有效的,但它是高度非惯用的。与将一元值作为输入传递给函数并将其绑定到函数内部,使用外部的绑定运算符(>>=)定义接受常规值并返回一元值的函数要常见得多。

所以更正常的是

代码语言:javascript
复制
shiftAdd :: Int -> StateT [Int] IO Int
shiftAdd i = do
  [j] <- state (splitAt 1)
  return (i + j)

所以现在我们不仅可以

代码语言:javascript
复制
>>> runStateT (shiftAdd 55) [1,2,3]
(56,[2,3])

但同时也

代码语言:javascript
复制
>>> runStateT (shiftAdd 55 >>= shiftAdd >>= shiftAdd)
(61,[])

它仍然不像它可能是那样的习语:

  • 我使用splitAt进行了不必要的局部处理(如果状态列表为空,它将引发异常)
  • 这是不必要的特定(根本不使用IO,但我们不能将它与其他基本单体一起使用)

解决这个问题会让我们:

代码语言:javascript
复制
shiftAdd' :: (Monad m, Num a) => a -> StateT [a] m a
shiftAdd' i = state $ \js -> case js of
  [] -> (i, [])
  j : js -> (i + j, js)

效果很好:

代码语言:javascript
复制
>>> 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,[])
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44025232

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档