2014-09-29 4 views
4

Я читаю главу 9 (Больше ввода и больше вывода) Учите вас в Haskell для отличного хорошего. Теперь я собираюсь научиться генерировать случайные числа в Haskell (это так интересно!). Вот цитата из книги:Генерация случайных чисел в Haskell

Чтобы вручную создать случайный генератор, используйте mkStdGenfunction. Он имеет тип mkStdGen :: Int -> StdGen. Он принимает целое число и, основываясь на этом, дает нам случайный генератор. Итак, давайте попробуем использовать random и mkStdGenin тандем, чтобы получить (вряд ли) случайное число.

ghci> random (mkStdGen 100) 
<interactive>:1:0: 
Ambiguous type variable `a' in the constraint: 
`Random a' arising from a use of `random' at <interactive>:1:0-20 
Probable fix: add a type signature that fixes these type variable(s) 

Что это? Ах, правильно, функция random может возвращать значение любого типа, входящего в класс типа Random, поэтому нам нужно сообщить Haskell, какой тип мы хотим. Также давайте не будем забывать, что он возвращает случайное значение и случайный генератор в паре.

Проблема заключается в том, что я не получаю эту ошибку, на самом деле, я могу сделать следующее:

*Main> :m + System.Random 
*Main System.Random> random (mkStdGen 100) 
(-3633736515773289454,693699796 2103410263) 

Так что мой вопрос, почему я могу оценить это выражение не получая исключение?

+0

Просто короткое примечание к будущему: если вы действительно хотите использовать случайные числа в Haskell, пакет mwc-random будет быстрее и генерирует более качественные случайные числа. – tibbe

ответ

10

Я бы предпочел и сказал, что правила по умолчанию для GHCI были расширены с момента написания LYAH. Это означает, что в случаях, когда тип неоднозначен, GHCI пытается выбрать конкретный тип. В этом случае это выглядит как random (mkStdGen 100) по умолчанию (Integer, StdGen).

Если с другой стороны, я сделать файл test.hs

import System.Random 

foo = random (mkStdGen 100) 

... и попытаться загрузить его в GHCI, я получаю:

test.hs:3:7: 
    No instance for (Random a0) arising from a use of ‘random’ 
    The type variable ‘a0’ is ambiguous 
    Relevant bindings include 
     foo :: (a0, StdGen) (bound at test.hs:3:1) 
    Note: there are several potential instances: 
     instance Random Bool -- Defined in ‘System.Random’ 
     instance Random Foreign.C.Types.CChar -- Defined in ‘System.Random’ 
     instance Random Foreign.C.Types.CDouble 
     -- Defined in ‘System.Random’ 
     ...plus 33 others 
    In the expression: random (mkStdGen 100) 
    In an equation for ‘foo’: foo = random (mkStdGen 100) 
Failed, modules loaded: none. 

Если бы я хотел того же результата , я бы исправить тип foo, например, так:

foo :: (Integer, StdGen) 
foo = random (mkStdGen 100) 

для получения дополнительной информации о расширенном недобросовестном см section 2.4.8 in the GHC docs

+0

Одна уловка, на мой взгляд, вероятно, играет здесь: «случайный» метод может свободно модифицировать генератор по-разному в зависимости от типа. Если вместо этого генератор генерировал значения «Int», и у вас был метод «intToRandom» для использования результатов, тогда не было бы проблем с его использованием для получения полиморфных рандомов. Но есть очень веские причины для того, чтобы он был таким, каким он есть, особенно, что разные типы требуют разного количества случайности. – dfeuer

+0

Я бы поспорил, что недавние GHCi вводят типы с экземплярами Show для отображения результатов. 'let r = random $ mkStdGen 100' сохраняет полиморфный тип случайного значения с ограничением' Random' 'r :: Random a => (a, StdGen)', только при отображении выводится на экземпляр 'Int' или' Integer'. –

+1

Замечание, вы можете отключить расширенные правила по умолчанию с помощью ': set -XNoExtendedDefaultRules' в GHCi. Когда этот флаг установлен, возникает ошибка (хотя сообщение отличается от сообщения в LYAH). – bheklilr

Смежные вопросы