我有以下数据类型:
data Card = Card One | Card Two | ...
data Deck = Deck [Card]
我想在卡组中洗牌机
这是我到目前为止的位置:
import System.Random
shuffle :: Deck -> Deck
shuffle (Deck c) = Deck $ shuffleOnce randomN c
where randomN = randomIO >>= (\x -> return (x `mod` 52))
shuffleOnce n c = (findNth n c : deleteNth n c)
findNth 0 (x:_) = x
findNth n (_:xs) = findNth (n-1) xs
deleteNth 0 (_:xs) = xs
deleteNth n (x:xs) = x : (deleteNth (n-1) xs)
问题(显然)在这里:
where randomN = randomIO >>= (\x -> return (x `mod` 52))
我不知道如何使用IO
单子生成随机数。在单调的情况下将随机数从`换为52后,如何将其取出?
或者更好的问题,我实际上是如何洗牌?
请帮助。完整代码here
答案 0 :(得分:2)
编译器说,问题出在centralManagerDidUpdateState
中。 (randomN 1)
函数用一个参数调用,但是不接受。
然后就无法确定是哪种类型的随机数,因此我们需要在此处提供一个:
randomN
然后收到randomIO >>= (\x -> return (x `mod` 52)) :: IO Int
错误,这实际上意味着应该No instance for (Eq (IO Int))
,但是提供了Int
。为了方便起见,我们可以交换IO Int
的参数,并将此函数称为:
shuffleOnce n c
之后,错误提示:
shuffleOnce c <$> randomN
我们需要再次使用Expected type: [Card]
Actual type: IO [Card]
而不是<$>
,只是为了获得“内部” $
:
IO
因此,我们收到:
Deck <$> shuffleOnce c <$> randomN
我们对此无能为力,但可以更改Couldn't match expected type ‘Deck’ with actual type ‘IO Deck’
函数的类型:
shuffle
然后我们意识到,shuffle :: Deck -> IO Deck
shuffle (Deck c) = Deck <$> shuffleOnce c <$> randomN
where randomN = randomIO >>= (\x -> return (x `mod` 52)) :: IO Int
shuffleOnce c n = (findNth n c : deleteNth n c)
findNth 0 (x:_) = x
findNth n (_:xs) = findNth (n-1) xs
deleteNth 0 (_:xs) = xs
deleteNth n (x:xs) = x : (deleteNth (n-1) xs)
是一个具有副作用的函数,因为它包含随机数,这些随机数是“从外部世界接收的”。实际上,在类型定义中包含此信息似乎合乎逻辑。