2012-01-14 2 views
1

Я хочу сгенерировать список случайных чисел, где диапазон каждого случайного числа определяется элементами предоставленного списка. Я думал, что-то, что имело смысл, но я получаю ошибки я не понимаю :(Создание списка случайных чисел с помощью foldM

Вот что у меня есть:

useRNG nums min = do 
    generator <- get 
    let (val, generator') = randomR (min, 51) generator 
    put generator' 
    return $ val : nums 

foldM useRNG [] [0 .. 50] 

Может кто-нибудь помочь мне

ответ

4

Проблема заключается в том, что? useRNG может генерировать все виды чисел (любой экземпляр Random), и работать во всех видах монад (любое состояние монады, состояние которого является экземпляром RandomGen), как можно видеть из его предполагаемого типа подписи:

GHCi> :t useRNG 
useRNG 
    :: (MonadState s m, RandomGen s, Random a, Num a) => 
    [a] -> a -> m [a] 

... но когда вы его используете, вы не указали , который конкретных типов вы действительно хотите.

Если вы неоднозначности с сигнатурой типа:

test :: State StdGen [Int] 
test = foldM useRNG [] [0 .. 50] 

то он работает отлично. Вы также можете сделать это, поставив подпись типа на useRNG:

useRNG :: [Int] -> Int -> State StdGen [Int] 

Теперь, вы можете подумать: если useRNG отлично работает со всеми этими типами, почему не может test тоже? Ответ: monomorphism restriction, который довольно загадочен и не очень понравился многим пользователям Haskell. Вы можете избежать этого, либо поставив

{-# LANGUAGE NoMonomorphismRestriction #-} 

в верхней части файла, или давая test явный тип подписи:

test :: (RandomGen g, Random a, Num a, Enum a, MonadState g m) => m [a] 

Вы можете узнать правильную сигнатуру типа с GHCi:

GHCi> :t foldM useRNG [] [0 .. 50] 
foldM useRNG [] [0 .. 50] 
    :: (MonadState s m, RandomGen s, Random b, Num b, Enum b) => m [b] 

(Я написал явную подпись типа перед проверкой с помощью GHCi, поэтому моя немного отличается.)

Тем не менее, подпись этого типа немного полиморфный для практических целей - вы в основном ставите неоднозначность, пока не наработаете результат, поэтому я бы предложил уточнить его более конкретно в этом случае. Вы могли бы, например, держать test родовыми над типом случайного числа без ненужного полиморфизма над государственной монадой и генератором типа:

test :: (Random a, Num a, Enum a) => State StdGen [a] 

Вы могли бы также рассмотреть возможность использования MonadRandom, который оборачивает все стандартное случайное число в государственном монад-интерфейсе, поэтому вам не обязательно :)

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