Изучай Haskell во имя добра! (Липовача) - страница 144

>(–1352021624,651872571 1655838864)

Как и следовало ожидать! Тот же результат для тех же параметров. Так что давайте-ка передадим другой генератор в пара метре.

>ghci> random (mkStdGen 949494) :: (Int, StdGen)

>(539963926,466647808 1655838864)

Отлично, получили другое число. Мы можем использовать аннотацию типа для того, чтобы получать случайные значения разных типов.

>ghci> random (mkStdGen 949488) :: (Float, StdGen)

>(0.8938442,1597344447 1655838864)

>ghci> random (mkStdGen 949488) :: (Bool, StdGen)

>(False,1485632275 40692)

>ghci> random (mkStdGen 949488) :: (Integer, StdGen)

>(1691547873,1597344447 1655838864)

Подбрасывание монет

Давайте напишем функцию, которая эмулирует трёхкратное подбрасывание монеты. Если бы функция >random не возвращала новый генератор вместе со случайным значением, нам пришлось бы передавать в функцию три случайных генератора в качестве параметров и затем возвращать результат подбрасывания монеты для каждого из них. Но это выглядит не очень разумным, потому что если один генератор может создавать случайные значения типа >Int (а он может принимать довольно много разных значений), его должно хватить и на троекратное подбрасывание монеты (что даёт нам в точности восемь комбинаций). В таких случаях оказывается очень полезно, что функция >random возвращает новый генератор вместе со значением.

Будем представлять монету с помощью >Bool. >True – это «орёл», а >False –«решка».

>threeCoins :: StdGen –> (Bool, Bool, Bool)

>threeCoins gen =

>   let (firstCoin, newGen) = random gen

>       (secondCoin, newGen') = random newGen

>       (thirdCoin, newGen'') = random newGen'

>   in  (firstCoin, secondCoin, thirdCoin)

Мы вызываем функцию >random с генератором, который нам передали в параметре, и получаем монету и новый генератор. Затем снова вызываем функцию >random, но на этот раз с новым генератором, чтобы получить вторую монету. Делаем то же самое с третьей монетой. Если бы мы вызывали функцию >random с одним генератором, все монеты имели бы одинаковое значение, и в результате мы могли бы получать только >(False, False, False) или >(True, True, True).

>ghci> threeCoins (mkStdGen 21)

>(True,True,True)

>ghci> threeCoins (mkStdGen 22)

>(True,False,True)

>ghci> threeCoins (mkStdGen 943)

>(True,False,True)

>ghci> threeCoins (mkStdGen 944)

>(True,True,True)

Обратите внимание, что нам не надо писать >random gen :: (Bool, StdGen): ведь мы уже указали, что мы желаем получить булевское значение, в декларации типа функции. По декларации язык Haskell может вычислить, что нам в данном случае нужно получить булевское значение.