Проблема заключается в том, что? 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, который оборачивает все стандартное случайное число в государственном монад-интерфейсе, поэтому вам не обязательно :)