操纵 Haskell Monad 状态
Manipulating Haskell Monad State
有点类似于,我在想办法
如何在 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
- 递归处理列表的其余部分
- 将两个结果放回一起,并将它们用作 return 值进行
State
ful 计算。
scanTeam :: [Employee] -> State (Int,Int) [Employee']
scanTeam [ ] = return []
scanTeam (p:ps) = do
newP <- scanEmployee p
newPs <- scanTeam ps
return (newP:newPs)
事实证明,“map
in a monadic context”在一般情况下非常有用,所以它在标准前奏中作为 mapM :: Monad m => (a -> m b) -> [a] -> m [b]
(aka traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
出现,如果你准备好接受兔子的话洞)。
scanTeam = mapM scanEmployee
有点类似于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
- 递归处理列表的其余部分
- 将两个结果放回一起,并将它们用作 return 值进行
State
ful 计算。
scanTeam :: [Employee] -> State (Int,Int) [Employee']
scanTeam [ ] = return []
scanTeam (p:ps) = do
newP <- scanEmployee p
newPs <- scanTeam ps
return (newP:newPs)
事实证明,“map
in a monadic context”在一般情况下非常有用,所以它在标准前奏中作为 mapM :: Monad m => (a -> m b) -> [a] -> m [b]
(aka traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
出现,如果你准备好接受兔子的话洞)。
scanTeam = mapM scanEmployee