有点类似于this question,我正在尝试找出
如何绕过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
一起使用。到目前为止,我失败了。
实际上,我什至不确定状态是否可以在它们之间移动(?)。
答案 0 :(得分:4)
由于State
是monad,因此可以使用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