Проблемы, чтобы сделать функцию, которая катит NDice в Haskell - PullRequest
1 голос
/ 05 ноября 2019

Я экспериментирую со случайностью в Haskell, и я хотел сделать функцию, которая бы давала Int n, возвращает список состояний случайных чисел от 1 до 6:

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

rollNDice :: Int -> State StdGen [Int]
rollNDice n | n == 0    = [] :: State StdGen [Int]
  | otherwise = (:) <$> rollDie <*> rollNDice (n-1)

, но когда я пытаюсьзапустить его в ghci я получаю:

Couldn't match type ‘[a0]’
                     with ‘StateT StdGen Data.Functor.Identity.Identity [Int]’
      Expected type: State StdGen [Int]
        Actual type: [a0]
    • In the expression: [] :: State StdGen [Int]
      In an equation for ‘rollNDice’:
          rollNDice n
            | n == 0 = [] :: State StdGen [Int]
            | otherwise = (:) <$> rollDie <*> rollNDice (n - 1)

Я не понимаю, ошибка. Есть идеи?

1 Ответ

4 голосов
/ 05 ноября 2019

Причина, по которой это не работает, заключается в том, что [] имеет тип [a], вы не можете использовать [] :: State StdGen [Int] для преобразования его в State StdGen [Int].

Однако вы можете использовать pure :: Applicative m => a -> m a, чтобы обернуть это в State StdGen [Int]:

rollNDice :: Int -> State StdGen [Int]
rollNDice 0 = <b>pure []</b>
rollNDice n = (:) <$> rollDie <*> rollNDice (n-1)

При этом вы можете использовать replicateM :: Applicative m => Int -> m a -> m [a] здесь для генерации списка n элементов:

import Control.Monad(replicateM)

rollNDice :: Int -> State StdGen [Int]
rollNDice = (<b>`replicateM` rollDie</b>)

Например:

Prelude System.Random Control.Monad.Trans.State Control.Monad> evalState (rollNDice 5) (mkStdGen 0)
[6,6,4,1,5]
...