Недавно изменился API Control.Monad.State? - программирование

Недавно изменился API Control.Monad.State?

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

Примеры в монаде State в разделе "Learn You A Haskell" (и номер прочее учебники), скажем, что State определяется как:

newtype State s a = State { runState :: s -> (a,s) }

Мне нужно передать функцию типа s -> (a,s) (которая может или не может быть указана в других аргументах) конструктору значения State. Поэтому мои функции выглядят так:

pop :: Ord a => State (Heap a) a
pop = State pop'
pop' :: Ord a => Heap a -> (a, Heap a)
-- implementation of pop' goes here

push :: Ord a => a -> State (Heap a) ()
push item = State $ push' item
push' :: Ord a => a -> Heap a -> ((), Heap a)
-- implementation of push' goes here

Это не скомпилируется со следующей ошибкой:

Not in scope: data constructor `State'
Perhaps you meant `StateT' (imported from Control.Monad.State)

Из чтения API docs для Control.Monad.State, похоже, что конструктор значения State был удален из модуля, поскольку эти Учебники были написаны. Как новичок, я считаю, что документация далека от объяснений. Поэтому мой вопрос:

  • Я прав, полагая, что конструктор значения State отсутствует?
  • Что я должен использовать вместо этого?
4b9b3361

Ответ 1

  • Да, он ушел, заменен на StateT. (Монада State теперь определена в терминах монадного трансформатора StateT.)
  • Вместо этого вы должны использовать State.

Я бы спросил, правильно ли ваш подход. Вместо того, чтобы беспокоиться о том, как реализуется State, рассмотрите возможность использования do-notation и функций get и put.

Ответ 2

Вот правильные реализации примеров, показанных в книге, связанных с государственной монадой:

MONADIC STACK:

-- MonadicStack.hs (Learn You a Haskell for Great Good!)

import Control.Monad.State  

type Stack = [Int]

pop :: State Stack Int
-- The following line was wrong in the book:
-- pop = State $ \(x:xs) -> (x,xs)  
pop = do
 x:xs <- get
 put xs
 return x

push :: Int -> State Stack ()  
-- The following line was wrong in the book:
-- push a = State $ \xs -> ((),a:xs)
push a = do
 xs <- get
 put (a:xs)
 return ()

pop1 = runState pop [1..5]
push1 = runState (push 1) [2..5]

stackManip :: State Stack Int  
stackManip = do  
 push 3  
 a <- pop  
 pop  

stackManip1 = runState stackManip [5,8,2,1]  
stackManip2 = runState stackManip [1,2,3,4]  

stackStuff :: State Stack ()  
stackStuff = do  
 a <- pop  
 if a == 5  
  then push 5  
  else do  
   push 3  
   push 8  

stackStuff1 = runState stackStuff [9,0,2,1,0]  
stackStuff2 = runState stackStuff [5,4,3,2,1]

moreStack :: State Stack ()  
moreStack = do  
 a <- stackManip  
 if a == 100  
  then stackStuff  
  else return ()  

moreStack1 = runState moreStack [100,9,0,2,1,0]
moreStack2 = runState moreStack [9,0,2,1,0]

stackyStack :: State Stack ()  
stackyStack = do  
 stackNow <- get  
 if stackNow == [1,2,3]  
  then put [8,3,1]  
  else put [9,2,1]  

stackyStack1 = runState stackyStack [1,2,3]
stackyStack2 = runState stackyStack [10,20,30,40]

МОНАДИЧЕСКИЕ СЛУЧАЙНЫЕ ГЕНЕРАТОРЫ:

-- MonadicRandomGenerator.hs (Learn You a Haskell for Great Good!)

import System.Random  
import Control.Monad.State  

randomSt :: (RandomGen g, Random a) => State g a  
-- The following line was wrong in the book:
-- randomSt = State random
randomSt = do
 gen <- get
 let (value,nextGen) = random gen
 put nextGen
 return value

randomSt1 = (runState randomSt (mkStdGen 1)) :: (Int,StdGen)
randomSt2 = (runState randomSt (mkStdGen 2)) :: (Float,StdGen)

threeCoins :: State StdGen (Bool,Bool,Bool)  
threeCoins = do  
 a <- randomSt  
 b <- randomSt  
 c <- randomSt  
 return (a,b,c)  

threeCoins1 = runState threeCoins (mkStdGen 33)
threeCoins2 = runState threeCoins (mkStdGen 2)

-- rollDie and rollNDice are not explained in the book LYAHFGG. 
-- But these functions are interesting and complementary:

rollDie :: State StdGen Int
rollDie = do 
 generator <- get
 let (value, newGenerator) = randomR (1,6) generator
 put newGenerator
 return value

rollDie1 = runState rollDie (mkStdGen 1)
rollDie2 = runState rollDie (mkStdGen 2)

rollNDice :: Int -> State StdGen [Int]
rollNDice 0 = do
 return []
rollNDice n = do
 value <- rollDie
 list <- rollNDice (n-1)
 return (value:list)

rollNDice1 = runState (rollNDice 10) (mkStdGen 1)
rollNDice2 = runState (rollNDice 20) (mkStdGen 2)

Ответ 3

Я думаю, что state делает сжатую реализацию pop, но modify лучше подходит для push, так как возвращает модуль:

import Control.Monad.State  

type Stack a = [a]

pop :: State (Stack a) a
pop = state $ \(a:as) -> (a, as)

push :: a -> State (Stack a) ()  
push a = modify (a:)

Ответ 4

РАЗМЕЩЕННЫЙ МОНАДИЧЕСКИЙ СТЕК:

-- DesugaredMonadicStack.hs (Learn You a Haskell for Great Good!)

import Control.Monad.State  

type Stack = [Int]

pop :: State Stack Int  
pop = 
 get >>=
 \(x:xs) -> put xs >>
 return x

push :: Int -> State Stack ()
push a =
 get >>=
 \xs -> put (a:xs) >>
 return ()

pop1 = runState pop [1..5]
push1 = runState (push 1) [2..5]

stackManip :: State Stack Int  
stackManip =
 push 3 >>
 pop >>=
 \a -> pop

stackManip1 = runState stackManip [5,8,2,1]  
stackManip2 = runState stackManip [1,2,3,4]  

stackStuff :: State Stack ()  
stackStuff =
 pop >>=
 \a -> 
  if a == 5 then
   push 5
  else
   push 3 >>
   push 8

stackStuff1 = runState stackStuff [9,0,2,1,0]  
stackStuff2 = runState stackStuff [5,4,3,2,1]

moreStack :: State Stack ()  
moreStack =
 stackManip >>=
 \a ->
  if a == 100 then
   stackStuff
  else
   return ()

moreStack1 = runState moreStack [100,9,0,2,1,0]
moreStack2 = runState moreStack [9,0,2,1,0]
moreStack3 = runState moreStack [100,5,4,3,2,1]

stackyStack :: State Stack ()  
stackyStack =
 get >>=
 \stackNow ->
  if stackNow == [1,2,3] then
   put [8,3,1]
  else
   put [9,2,1]

stackyStack1 = runState stackyStack [1,2,3]
stackyStack2 = runState stackyStack [10,20,30,40] 

РАЗНООБРАЗНЫЙ МОНАДИЧЕСКИЙ СЛУЧАЙНЫЙ ГЕНЕРАТОР:

-- DesugaredMonadicRandomGenerator.hs (Learn You a Haskell for Great Good!)

import System.Random  
import Control.Monad.State  

randomSt :: (RandomGen g, Random a) => State g a  
randomSt =
 get >>=
 \gen -> 
  let (value,nextGen) = random gen
  in
   put nextGen >>
   return value

randomSt1 = (runState randomSt (mkStdGen 1)) :: (Int,StdGen)
randomSt2 = (runState randomSt (mkStdGen 2)) :: (Float,StdGen)

threeCoins :: State StdGen (Bool,Bool,Bool)
threeCoins =
 randomSt >>=
 \a -> randomSt >>=
 \b -> randomSt >>=
 \c -> return (a,b,c)

threeCoins1 = runState threeCoins (mkStdGen 33)
threeCoins2 = runState threeCoins (mkStdGen 2)

-- rollDie and rollNDice are not explained in the book LYAHFGG. 
-- But these functions are interesting and complementary:

rollDie :: State StdGen Int
rollDie =
 get >>=
 \generator -> 
  let (value, newGenerator) = randomR (1,6) generator
  in
   put newGenerator >>
   return value

rollDie1 = runState rollDie (mkStdGen 1)
rollDie2 = runState rollDie (mkStdGen 2)

rollNDice :: Int -> State StdGen [Int]
rollNDice 0 = return []
rollNDice n =
 rollDie >>=
 \value -> rollNDice (n-1) >>=
 \list -> return (value:list)

rollNDice1 = runState (rollNDice 10) (mkStdGen 1)
rollNDice2 = runState (rollNDice 20) (mkStdGen 2)