haskell - 操纵 Haskell Monad 状态
问题描述
有点类似于这个问题,我试图弄清楚如何在 Haskell Monad 状态下移动。团队中的每个人都Employee
被替换为相应的Employee'
人,同时保持一些简单的状态。这是代码:
module Main( main ) where
import Control.Monad.State
data Employee = EmployeeSW Int Int | EmployeeHW Int String deriving ( Show )
data Employee' = EmployeeSW' Int | EmployeeHW' String deriving ( Show )
scanTeam :: [Employee] -> State (Int,Int) [Employee']
scanTeam [ ] = return []
scanTeam (p:ps) = scanEmployee p -- : scanTeam ps ???
scanEmployee :: Employee -> State (Int,Int) Employee'
scanEmployee (EmployeeSW id s) = do
(num,raise) <- get
put (num+1,raise)
return (EmployeeSW' (s+raise))
scanEmployee (EmployeeHW id s) = do
(num,raise) <- get
put (num+1,raise)
return (EmployeeHW' (s++(show raise)))
startState = (0,3000)
t = [(EmployeeHW 77 "Hundred"),(EmployeeSW 66 500),(EmployeeSW 32 200)]
main = print $ evalState (scanTeam t) startState
我想最终scanEmployee p
与连接scanTeam ps
,所以我尝试提取 的片段scanEmployee p
并以某种方式将它们与scanTeam ps
. 到目前为止,我失败得很惨。实际上,我什至不确定状态是否可以在它们之间移动(?)。
解决方案
由于State
是一个单子,您可以使用do
符号来定义State
计算。(State
的实例检测Monad
状态,因此块中一个语句的结束状态成为下一个语句do
的开始状态。)
因此,在一个do
块中,我将:
- 处理
Employee
列表中的第一个以获得新的Employee
- 递归处理列表的其余部分
- 将两个结果重新组合在一起,并将它们用作
State
ful 计算的返回值。
scanTeam :: [Employee] -> State (Int,Int) [Employee']
scanTeam [ ] = return []
scanTeam (p:ps) = do
newP <- scanEmployee p
newPs <- scanTeam ps
return (newP:newPs)
事实证明,“map
在单子上下文中”通常非常有用,因此它出现在标准前奏中mapM :: Monad m => (a -> m b) -> [a] -> m [b]
(又名traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
,如果你准备好进入兔子洞)。
scanTeam = mapM scanEmployee
推荐阅读
- git - Git远程存储库与本地存储库的文件结构不同
- swift - 通过 prepareForSegue 将标签设置为按钮
- python - Selenium throwing [Errno 54] 任何 python 暂停由对等方重置连接
- c# - if 语句可以与使用模式匹配的变量赋值相结合吗?
- python - Python Selenium:元素当前不可见,可能无法操作
- linux - 我看到一个不正确的 pid
- javascript - 传单 gdal2tile wgs84 lat long to map point
- java - Firestore如何从文档引用包含特定查询路径的集合中查询数据
- python - 将 UTC 时间字符串的 pandas 数据框列转换为浮点数
- ruby-on-rails - Rails - 如何编写一个链接,该链接将被调用以在控制器中调用带有参数的操作?