Манипулирование штатом Хаскелл - PullRequest
0 голосов
/ 02 марта 2019

Чем-то похож на этот вопрос , я пытаюсь выяснить, как перемещаться по состоянию Монады Хаскелла.Каждый 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.Пока что я с треском провалился.На самом деле, я даже не уверен, что состояние может быть перемещено между ними (?).

1 Ответ

0 голосов
/ 02 марта 2019

Поскольку State является монадой, вы можете использовать нотацию do для определения State вычислений.(Экземпляр State Monad управляет состоянием, поэтому конечное состояние одного оператора в блоке do становится начальным состоянием следующего.)

Итак, в do block, я собираюсь:

  1. Обработать первый Employee в списке, чтобы получить новый Employee
  2. Обрабатывать остальную часть списка рекурсивно
  3. Соедините два результата вместе и используйте их в качестве возвращаемого значения для вычисления State.
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
...