Я работаю над лабораторией, в которой мы работаем со случайностью и монадами.Haskell: Shuffling deck
Части лаборатории являются:
- написать функцию RandR, которая генерирует случайное число в заданном диапазоне
- написать функцию rollTwoDice, которая имитирует прокатки две кости
- написать функцию removeCard, которая случайно удаляет карту из списка PlayingCards
- напишите функцию shuffleDeck, которая берет удаленную карту, кладет ее перед колодой, а затем повторяет, пока колода полностью не перепутана.
Я сделал 1, 2, и 3, но у меня возникают проблемы с 4.
Вот данный код:
RandState.hs
module RandState where
import UCState
import System.Random
-- In order to generate pseudo-random numbers, need to pass around generator
-- state in State monad
type RandState a = State StdGen a
-- runRandom runs a RandState monad, given an initial random number generator
runRandom :: RandState a -> StdGen -> a
runRandom (State f) s = res
where (res, state) = f s
-- rand is a helper function that generates a random instance of any
-- type in the Random class, using the RandState monad.
rand :: Random a => RandState a
rand = do
gen <- get
let (x, gen') = random gen
put gen'
return x
UCState. hs
{-
- Simplified implementation of the State monad. The real implementation
- is in the Control.Monad.State module: using that is recommended for real
- programs.
-}
module UCState where
data State s a = State { runState :: s -> (a, s) }
instance Monad (State s)
where
{-
- return lifts a function x up into the state monad, turning it into
- a state function that just passes through the state it receives
-}
return x = State (\s -> (x, s))
{-
- The >>= combinator combines two functions p and f, and
- gives back a new function (Note: p is originally wrapped in the
- State monad)
-
- p: a function that takes the initial state (from right at the start
- of the monad chain), and gives back a new state and value,
- corresponding to the result of the chain up until this >>=
- f: a function representing the rest of the chain of >>='s
-}
(State p) >>= f = State (\initState ->
let (res, newState) = p initState
(State g) = f res
in g newState)
-- Get the state
get :: State s s
get = State (\s -> (s, s))
-- Update the state
put :: s -> State s()
put s = State (\_ -> ((), s))
Вот мой код, который я только что написал внутри RandS tate.hs, так как я не мог понять, как импортировать его (помощь с импортом было бы хорошо, как хорошо, хотя и не то, что я больше всего беспокоит на данный момент):
randR :: Random a => (a, a) -> RandState a
randR (lo, hi) = do
gen <- get
let (x, gen') = randomR (lo, hi) gen
put gen'
return x
testRandR1 :: IO Bool
testRandR1 = do
gen <- newStdGen
let genR = runRandom (randR (1,5)) gen :: Int
return (genR <=5 && genR >=1)
testRandR2 :: IO Bool
testRandR2 = do
gen <- newStdGen
let genR = runRandom (randR (10.0, 11.5)) gen :: Double
return (genR <= 11.5 && genR >= 10.0)
rollTwoDice :: RandState Int
rollTwoDice = do
gen <- get
let (a, gen') = randomR (1, 6) gen :: (Int, StdGen)
put gen'
let (b, gen'') = randomR (1, 6) gen' :: (Int, StdGen)
put gen''
return $ a + b
testRollTwoDice :: IO Bool
testRollTwoDice = do
gen <- newStdGen
let genR = runRandom (rollTwoDice) gen
return (genR <= 12 && genR >= 2)
-- Data types to represent playing cards
data CardValue = King | Queen | Jack | NumberCard Int
deriving (Show, Eq)
data CardSuit = Hearts | Diamonds | Spades | Clubs
deriving (Show, Eq)
data PlayingCard = PlayingCard CardSuit CardValue
deriving (Show, Eq)
{-
- fullCardDeck will be a deck of cards, 52 in total, with a King, a Queen,
- a Jack and NumberCards from 1 to 10 for each suit.
-}
-- fullCardDeck and its definition were given in the lab
fullCardDeck :: [PlayingCard]
fullCardDeck = [ PlayingCard s v | s <- allsuits, v <- allvals ] where
allvals = King : Queen : Jack : [ NumberCard i | i <- [1..10] ]
allsuits = [Hearts, Diamonds, Spades, Clubs]
removeCard :: [a] -> RandState [a]
removeCard deck = do
gen <- get
let n = runRandom (randR(1, length (deck))) gen :: Int
let (xs, ys) = splitAt (n-1) deck
return $ head ys : xs ++ tail ys
shuffleDeck deck = do
gen <- get
let f deck = head $ runRandom (removeCard deck) gen
return $ take (length(deck)) (iterate f deck)
shuffleDeck не работает , Ошибка:
RandState.hs:88:31:
Occurs check: cannot construct the infinite type: a0 = [a0]
Expected type: [a0] -> [a0]
Actual type: [a0] -> a0
In the first argument of `iterate', namely `f'
In the second argument of `take', namely `(iterate f deck)'
In the second argument of `($)', namely `take 52 (iterate f deck)'
Я предполагаю, что проблема в том, что итерация принимает значение, применяет функцию к этому значению, функция применяется к результату, и так далее, возвращая бесконечный список результатов. Я передаю итерацию функции, которая принимает список, и возвращает карту, поэтому результат не может быть передан следующей итерации. Каким будет лучший способ подойти к этой проблеме (4)? Я также обеспокоен тем, что моя функция removeCard немного дергается, поскольку она просто помещает «удаленную» карту спереди, что я сделал, чтобы сделать shuffleDeck легче писать. В случае необходимости лучше всего подойти к этой проблеме (3)?
Спасибо, Джефф
мой лучший гость вынимают 'головы $' от е, как вы хотите перебрать всю палубу (а не над первой картой!). Это должно быть хотя бы typecheck. Редактировать: да, это так, вам придется исправить аргумент, но вы должны уметь это выяснить. – MdxBhmt
'import' должен импортировать вещи :) – jozefg
Спасибо MdxBhmt, я удалил голову $ из f, а затем отобразил голову в список с повторением. Я не могу получить shuffleDeck, чтобы отображать его результаты, хотя, по-видимому, потому, что нет экземпляра (Show (RandState [PlayingCard])). Есть идеи для этого? И jozefg, я уже пробовал делать импорт прошлой ночью, и это не сработало, но я просто попробовал это снова, и это сработало. Возможно, ваш комментарий был фактором x, поэтому спасибо. – Jeff